<!DOCTYPE HTML>
<html lang="zh-CN" class="sidebar-visible no-js light">
    <head>
        <!-- Book generated using mdBook -->
        <meta charset="UTF-8">
        <title>PurpleDragonBookAnswer</title>
        <meta name="robots" content="noindex" />


        <!-- Custom HTML head -->
        
        <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
        <meta name="description" content="Purple Dragon Book Answer Online Edition">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <meta name="theme-color" content="#ffffff" />

        <link rel="icon" href="favicon.svg">
        <link rel="shortcut icon" href="favicon.png">
        <link rel="stylesheet" href="css/variables.css">
        <link rel="stylesheet" href="css/general.css">
        <link rel="stylesheet" href="css/chrome.css">
        <link rel="stylesheet" href="css/print.css" media="print">

        <!-- Fonts -->
        <link rel="stylesheet" href="FontAwesome/css/font-awesome.css">
        <link rel="stylesheet" href="fonts/fonts.css">

        <!-- Highlight.js Stylesheets -->
        <link rel="stylesheet" href="highlight.css">
        <link rel="stylesheet" href="tomorrow-night.css">
        <link rel="stylesheet" href="ayu-highlight.css">

        <!-- Custom theme stylesheets -->

    </head>
    <body>
        <!-- Provide site root to javascript -->
        <script type="text/javascript">
            var path_to_root = "";
            var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "light";
        </script>

        <!-- Work around some values being stored in localStorage wrapped in quotes -->
        <script type="text/javascript">
            try {
                var theme = localStorage.getItem('mdbook-theme');
                var sidebar = localStorage.getItem('mdbook-sidebar');

                if (theme.startsWith('"') && theme.endsWith('"')) {
                    localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
                }

                if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
                    localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
                }
            } catch (e) { }
        </script>

        <!-- Set the theme before any content is loaded, prevents flash -->
        <script type="text/javascript">
            var theme;
            try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
            if (theme === null || theme === undefined) { theme = default_theme; }
            var html = document.querySelector('html');
            html.classList.remove('no-js')
            html.classList.remove('light')
            html.classList.add(theme);
            html.classList.add('js');
        </script>

        <!-- Hide / unhide sidebar before it is displayed -->
        <script type="text/javascript">
            var html = document.querySelector('html');
            var sidebar = 'hidden';
            if (document.body.clientWidth >= 1080) {
                try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
                sidebar = sidebar || 'visible';
            }
            html.classList.remove('sidebar-visible');
            html.classList.add("sidebar-" + sidebar);
        </script>

        <nav id="sidebar" class="sidebar" aria-label="Table of contents">
            <div class="sidebar-scrollbox">
                <ol class="chapter"><li class="chapter-item expanded "><a href="preface.html"><strong aria-hidden="true">1.</strong> Preface</a></li><li class="chapter-item expanded "><a href="ch01/ch01.html"><strong aria-hidden="true">2.</strong> Chapter 1</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="ch01/1.1/1.1.html"><strong aria-hidden="true">2.1.</strong> Section 1.1</a></li><li class="chapter-item expanded "><a href="ch01/1.3/1.3.html"><strong aria-hidden="true">2.2.</strong> Section 1.3</a></li><li class="chapter-item expanded "><a href="ch01/1.6/1.6.html"><strong aria-hidden="true">2.3.</strong> Section 1.6</a></li></ol></li><li class="chapter-item expanded "><a href="ch02/ch02.html"><strong aria-hidden="true">3.</strong> Chapter 2</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="ch02/key-point/key-point.html"><strong aria-hidden="true">3.1.</strong> KeyPoints</a></li><li class="chapter-item expanded "><a href="ch02/2.2/2.2.html"><strong aria-hidden="true">3.2.</strong> Section 2.2</a></li><li class="chapter-item expanded "><a href="ch02/2.3/2.3.html"><strong aria-hidden="true">3.3.</strong> Section 2.3</a></li><li class="chapter-item expanded "><a href="ch02/2.4/2.4.html"><strong aria-hidden="true">3.4.</strong> Section 2.4</a></li><li class="chapter-item expanded "><a href="ch02/2.6/2.6.html"><strong aria-hidden="true">3.5.</strong> Section 2.6</a></li><li class="chapter-item expanded "><a href="ch02/2.8/2.8.html"><strong aria-hidden="true">3.6.</strong> Section 2.8</a></li></ol></li><li class="chapter-item expanded "><a href="ch03/ch03.html"><strong aria-hidden="true">4.</strong> Chapter 3</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="ch03/key-point/key-point.html"><strong aria-hidden="true">4.1.</strong> KeyPoints</a></li><li class="chapter-item expanded "><a href="ch03/3.1/3.1.html"><strong aria-hidden="true">4.2.</strong> Section 3.1</a></li><li class="chapter-item expanded "><a href="ch03/3.3/3.3.html"><strong aria-hidden="true">4.3.</strong> Section 3.3</a></li><li class="chapter-item expanded "><a href="ch03/3.4/3.4.html"><strong aria-hidden="true">4.4.</strong> Section 3.4</a></li><li class="chapter-item expanded "><a href="ch03/3.5/3.5.html"><strong aria-hidden="true">4.5.</strong> Section 3.5</a></li><li class="chapter-item expanded "><a href="ch03/3.6/3.6.html"><strong aria-hidden="true">4.6.</strong> Section 3.6</a></li><li class="chapter-item expanded "><a href="ch03/3.7/3.7.html"><strong aria-hidden="true">4.7.</strong> Section 3.7</a></li><li class="chapter-item expanded "><a href="ch03/3.8/3.8.html"><strong aria-hidden="true">4.8.</strong> Section 3.8</a></li><li class="chapter-item expanded "><a href="ch03/3.9/3.9.html"><strong aria-hidden="true">4.9.</strong> Section 3.9</a></li></ol></li><li class="chapter-item expanded "><a href="ch04/ch04.html"><strong aria-hidden="true">5.</strong> Chapter 4</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="ch04/key-point/key-point.html"><strong aria-hidden="true">5.1.</strong> KeyPoints</a></li><li class="chapter-item expanded "><a href="ch04/4.2/4.2.html"><strong aria-hidden="true">5.2.</strong> Section 4.2</a></li><li class="chapter-item expanded "><a href="ch04/4.3/4.3.html"><strong aria-hidden="true">5.3.</strong> Section 4.3</a></li><li class="chapter-item expanded "><a href="ch04/4.4/4.4.html"><strong aria-hidden="true">5.4.</strong> Section 4.4</a></li><li class="chapter-item expanded "><a href="ch04/4.5/4.5.html"><strong aria-hidden="true">5.5.</strong> Section 4.5</a></li><li class="chapter-item expanded "><a href="ch04/4.6/4.6.html"><strong aria-hidden="true">5.6.</strong> Section 4.6</a></li><li class="chapter-item expanded "><a href="ch04/4.7/4.7.html"><strong aria-hidden="true">5.7.</strong> Section 4.7</a></li></ol></li><li class="chapter-item expanded "><a href="ch05/ch05.html"><strong aria-hidden="true">6.</strong> Chapter 5</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="ch05/5.1/5.1.html"><strong aria-hidden="true">6.1.</strong> Section 5.1</a></li><li class="chapter-item expanded "><a href="ch05/5.2/5.2.html"><strong aria-hidden="true">6.2.</strong> Section 5.2</a></li><li class="chapter-item expanded "><a href="ch05/5.3/5.3.html"><strong aria-hidden="true">6.3.</strong> Section 5.3</a></li><li class="chapter-item expanded "><a href="ch05/5.4/5.4.html"><strong aria-hidden="true">6.4.</strong> Section 5.4</a></li><li class="chapter-item expanded "><a href="ch05/5.5/5.5.html"><strong aria-hidden="true">6.5.</strong> Section 5.5</a></li></ol></li><li class="chapter-item expanded "><a href="ch06/ch06.html"><strong aria-hidden="true">7.</strong> Chapter 6</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="ch06/6.1/6.1.html"><strong aria-hidden="true">7.1.</strong> Section 6.1</a></li><li class="chapter-item expanded "><a href="ch06/6.2/6.2.html"><strong aria-hidden="true">7.2.</strong> Section 6.2</a></li><li class="chapter-item expanded "><a href="ch06/6.3/6.3.html"><strong aria-hidden="true">7.3.</strong> Section 6.3</a></li><li class="chapter-item expanded "><a href="ch06/6.4/6.4.html"><strong aria-hidden="true">7.4.</strong> Section 6.4</a></li><li class="chapter-item expanded "><a href="ch06/6.5/6.5.html"><strong aria-hidden="true">7.5.</strong> Section 6.5</a></li><li class="chapter-item expanded "><a href="ch06/6.6/6.6.html"><strong aria-hidden="true">7.6.</strong> Section 6.6</a></li><li class="chapter-item expanded "><a href="ch06/6.7/6.7.html"><strong aria-hidden="true">7.7.</strong> Section 6.7</a></li></ol></li><li class="chapter-item expanded "><a href="ch07/ch07.html"><strong aria-hidden="true">8.</strong> Chapter 7</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="ch07/7.2/7.2.html"><strong aria-hidden="true">8.1.</strong> Section 7.2</a></li><li class="chapter-item expanded "><a href="ch07/7.3/7.3.html"><strong aria-hidden="true">8.2.</strong> Section 7.3</a></li><li class="chapter-item expanded "><a href="ch07/7.3/7.4.html"><strong aria-hidden="true">8.3.</strong> Section 7.4</a></li><li class="chapter-item expanded "><a href="ch07/7.5/7.5.html"><strong aria-hidden="true">8.4.</strong> Section 7.5</a></li><li class="chapter-item expanded "><a href="ch07/7.6/7.6.html"><strong aria-hidden="true">8.5.</strong> Section 7.6</a></li><li class="chapter-item expanded "><a href="ch07/7.7/7.7.html"><strong aria-hidden="true">8.6.</strong> Section 7.7</a></li></ol></li><li class="chapter-item expanded "><a href="ch08/ch08.html"><strong aria-hidden="true">9.</strong> Chapter 8</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="ch08/8.2/8.2.html"><strong aria-hidden="true">9.1.</strong> Section 8.2</a></li><li class="chapter-item expanded "><a href="ch08/8.3/8.3.html"><strong aria-hidden="true">9.2.</strong> Section 8.3</a></li><li class="chapter-item expanded "><a href="ch08/8.4/8.4.html"><strong aria-hidden="true">9.3.</strong> Section 8.4</a></li><li class="chapter-item expanded "><a href="ch08/8.5/8.5.html"><strong aria-hidden="true">9.4.</strong> Section 8.5</a></li></ol></li></ol>
            </div>
            <div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
        </nav>

        <div id="page-wrapper" class="page-wrapper">

            <div class="page">
                                <div id="menu-bar-hover-placeholder"></div>
                <div id="menu-bar" class="menu-bar sticky bordered">
                    <div class="left-buttons">
                        <button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
                            <i class="fa fa-bars"></i>
                        </button>
                        <button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
                            <i class="fa fa-paint-brush"></i>
                        </button>
                        <ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
                            <li role="none"><button role="menuitem" class="theme" id="light">Light (default)</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
                        </ul>
                        <button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
                            <i class="fa fa-search"></i>
                        </button>
                    </div>

                    <h1 class="menu-title">PurpleDragonBookAnswer</h1>

                    <div class="right-buttons">
                        <a href="print.html" title="Print this book" aria-label="Print this book">
                            <i id="print-button" class="fa fa-print"></i>
                        </a>

                    </div>
                </div>

                <div id="search-wrapper" class="hidden">
                    <form id="searchbar-outer" class="searchbar-outer">
                        <input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
                    </form>
                    <div id="searchresults-outer" class="searchresults-outer hidden">
                        <div id="searchresults-header" class="searchresults-header"></div>
                        <ul id="searchresults">
                        </ul>
                    </div>
                </div>

                <!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
                <script type="text/javascript">
                    document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
                    document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
                    Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
                        link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
                    });
                </script>

                <div id="content" class="content">
                    <main>
                        <h1 id="preface"><a class="header" href="#preface">Preface</a></h1>
<p>This is the online edition of Purple Dragon Book Answer.</p>
<blockquote>
<p>Note: Not every problem on this book can be found here.</p>
</blockquote>
<p><a href="https://github.com/fool2fish/dragon-book-exercise-answers">The Origin Repository Is Here.</a></p>
<p>If you want to contribute, go to <a href="">this repository</a>.</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="chapter-1"><a class="header" href="#chapter-1">Chapter 1</a></h1>
<p>Chapter 1: Introduction</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="exercises-for-section-11"><a class="header" href="#exercises-for-section-11">Exercises for Section 1.1</a></h1>
<h3 id="111"><a class="header" href="#111">1.1.1</a></h3>
<p>What is the difference between a compiler and an interpreter?</p>
<h4 id="answer"><a class="header" href="#answer">Answer</a></h4>
<p>A compiler is a program that can read a program in one language - the source language - and translate it into an equivalent program in another language – the target language and report any errors in the source program that it detects during the translation process.</p>
<p>Interpreter directly executes the operations specified in the source program on inputs supplied by the user.</p>
<h3 id="112"><a class="header" href="#112">1.1.2</a></h3>
<p>What are the advantages of:
(a) a compiler over an interpreter
(b) an interpreter over a compiler?</p>
<h4 id="answer-1"><a class="header" href="#answer-1">Answer</a></h4>
<p>a. The machine-language target program produced by a compiler is usually much faster than an interpreter at mapping inputs to outputs.</p>
<p>b. An interpreter can usually give better error diagnostics than a compiler, because it executes the source program statement by statement.</p>
<h3 id="113"><a class="header" href="#113">1.1.3</a></h3>
<p>What advantages are there to a language-processing system in which the compiler
produces assembly language rather than machine language?</p>
<h4 id="answer-2"><a class="header" href="#answer-2">Answer</a></h4>
<p>The compiler may produce an assembly-language program as its output, because
assembly language is easier to produce as output and is easier to debug.</p>
<h3 id="114"><a class="header" href="#114">1.1.4</a></h3>
<p>A compiler that translates a high-level language into another high-level
language is called a <em>source-to-source</em> translator. What advantages are there to
using C as a target language for a compiler?</p>
<h4 id="answer-3"><a class="header" href="#answer-3">Answer</a></h4>
<p>For the C language there are many compilers available that compile to almost
every hardware.</p>
<h3 id="115"><a class="header" href="#115">1.1.5</a></h3>
<p>Describe some of the tasks that an assembler needs to perform.</p>
<h4 id="answer-4"><a class="header" href="#answer-4">Answer</a></h4>
<p>It translates from the assembly language to machine code. This machine code is
relocatable.</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="exercises-for-section-13"><a class="header" href="#exercises-for-section-13">Exercises for Section 1.3</a></h1>
<h3 id="131"><a class="header" href="#131">1.3.1</a></h3>
<p>Indicate which of the following terms:</p>
<p>a. imperative
b. declarative
c. von Neumann
d. object-oriented
e. functional
f. third-generation
g. fourth-generation
h. scripting</p>
<p>apply to which of the following languages:</p>
<ol>
<li>C</li>
<li>C++</li>
<li>Cobol</li>
<li>Fortran</li>
<li>Java</li>
<li>Lisp</li>
<li>ML</li>
<li>Perl</li>
<li>Python</li>
<li>VB.</li>
</ol>
<h4 id="answer-5"><a class="header" href="#answer-5">Answer</a></h4>
<p>imperative: C, C++</p>
<p>object-oriented: C++, Java</p>
<p>functional: ML</p>
<p>scripting: Perl, Python</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="exercises-for-section-16"><a class="header" href="#exercises-for-section-16">Exercises for Section 1.6</a></h1>
<h3 id="161"><a class="header" href="#161">1.6.1</a></h3>
<p>For the block-structured C code below, indicate the values assigned to w, x, y, and z.</p>
<pre><code>int w, x, y, z;
int i = 4; int j = 5;
{
  int j = 7;
  i = 6;
  w = i + j;
}
x = i + j;
{
  int i = 8;
  y = i + j;
}
z = i + j;
</code></pre>
<h4 id="answer-6"><a class="header" href="#answer-6">Answer</a></h4>
<p>w = 13, x = 11, y = 13, z = 11.</p>
<h3 id="162"><a class="header" href="#162">1.6.2</a></h3>
<p>Repeat Exercise 1.6.1 for the code below.</p>
<pre><code>int w, x, y, z;
int i = 3; int j = 4;
{
  int i = 5;
  w = i + j;
}
x = i + j;
{
  int j = 6;
  i = 7;
  y = i + j;
}
z = i + j;
</code></pre>
<h4 id="answer-7"><a class="header" href="#answer-7">Answer</a></h4>
<p>w = 9, x = 7, y = 13, z = 11.</p>
<h3 id="163"><a class="header" href="#163">1.6.3</a></h3>
<p>For the block-structured code of Fig. 1.14, assuming the usual static scoping of
declarations, give the scope for each of the twelve declarations.</p>
<h4 id="answer-8"><a class="header" href="#answer-8">Answer</a></h4>
<pre><code>Block B1:
	declarations:  -&gt;   scope
		w				B1-B3-B4
		x				B1-B2-B4
		y				B1-B5
		z				B1-B2-B5
Block B2:
	declarations:  -&gt;   scope
		x				B2-B3
		z				B2
Block B3:
	declarations:  -&gt;   scope
		w				B3
		x				B3
Block B4:
	declarations:  -&gt;   scope
		w				B4
		x				B4
Block B5:
	declarations:  -&gt;   scope
		y				B5
		z				B5
</code></pre>
<h3 id="164"><a class="header" href="#164">1.6.4</a></h3>
<p>What is printed by the following C code?</p>
<pre><code>#define a (x + 1)
int x = 2;
void b() { x = a; printf(&quot;%d\n&quot;, x); }
void c() { int x = 1; printf(&quot;%d\n&quot;, a); }
void main () { b(); c(); }
</code></pre>
<h4 id="answer-9"><a class="header" href="#answer-9">Answer</a></h4>
<p>3</p>
<p>2</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="chapter-2"><a class="header" href="#chapter-2">Chapter 2</a></h1>
<p>Chapter 2: A Simple Syntax-Directed Translator</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="第2章要点"><a class="header" href="#第2章要点">第2章要点</a></h1>
<h3 id="1-文法语法制导翻译方案语法制导的翻译器"><a class="header" href="#1-文法语法制导翻译方案语法制导的翻译器">1. 文法、语法制导翻译方案、语法制导的翻译器</a></h3>
<p>以一个仅支持个位数加减法的表达式为例</p>
<ol>
<li>
<p>文法</p>
<p>list -&gt; list + digit | list - digit | digit</p>
<p>digit -&gt; 0 | 1 | … | 9</p>
</li>
<li>
<p>（消除了左递归的）语法制导翻译方案</p>
<p>expr -&gt; term rest</p>
<p>rest -&gt; + term { print('+') } rest | - term { print('+') } rest | ε</p>
<p>term -&gt; 0 { print('0') } | 1 { print('1') } | … | 9 { print('9') }</p>
</li>
<li>
<p>语法制导的翻译器</p>
<p>java代码见 p46</p>
</li>
</ol>
<h3 id="2-语法树语法分析树"><a class="header" href="#2-语法树语法分析树">2. 语法树、语法分析树</a></h3>
<p>以 2 + 5 - 9 为例</p>
<p><img src="ch02/key-point/./assets/dragonbook-keypoint-2.2-2.png" alt="语法树和语法分析树" /></p>
<h3 id="3-正则文法上下文无关文法上下文相关文法"><a class="header" href="#3-正则文法上下文无关文法上下文相关文法">3. 正则文法、上下文无关文法、上下文相关文法?</a></h3>
<p>文法缩写：</p>
<ul>
<li>RG：<a href="http://en.wikipedia.org/wiki/Regular_grammar">正则文法</a></li>
<li>CFG：<a href="http://en.wikipedia.org/wiki/Context-free_grammar">上下文无关文法</a></li>
<li>CSG：<a href="http://en.wikipedia.org/wiki/Context-sensitive_grammar">上下文相关文法</a></li>
</ul>
<h4 id="正则文法"><a class="header" href="#正则文法">正则文法</a></h4>
<p><a href="http://en.wikipedia.org/wiki/Regular_grammar">wiki</a></p>
<p>正则文法在标准之后所有产生式都应该满足下面三种情形中的一种：</p>
<pre><code>B -&gt; a
B -&gt; a C
B -&gt; epsilon
</code></pre>
<p>关键点在于：</p>
<ol>
<li>产生式的左手边必须是一个非终结符。</li>
<li>产生式的右手边可以什么都没有，可以有一个终结符，也可以有一个终结符加一个非终结符。</li>
</ol>
<p>从产生式的角度看，这样的规定使得每应用一条产生规则，就可以产生出零或一个终结符，直到最后产生出我们要的那个字符串。</p>
<p>从匹配的角度看，这样的规定使得每应用一条规则，就可以消耗掉一个非终结符，直到整个字符串被匹配掉。</p>
<p>这样定义的语言所对应的自动机有一种性质：有限状态自动机。</p>
<p>简单来说就是只需要记录当前的一个状态，和得到下一个输入符号，就可以决定接下来的状态迁移。</p>
<h4 id="正则文法和上下文无关文法"><a class="header" href="#正则文法和上下文无关文法">正则文法和上下文无关文法</a></h4>
<p>CFG 跟 RG 最大的区别就是，产生式的右手边可以有零或多个终结符或非终结符，顺序和个数都没限制。</p>
<p>想像一个经典例子，括号的配对匹配：</p>
<p>expr -&gt; '(' expr ')' | epsilon</p>
<p>这个产生式里（先只看第一个子产生式），右手边有一个非终结符 expr，但它的左右两侧都有终结符，这种产生式无法被标准化为严格的 RG 。这就是CFG的一个例子。</p>
<p>它对应的自动机就不只要记录当前的一个状态，还得外加记录到达当前位置的历史，才可以根据下一个输入符号决定状态迁移。所谓的“历史”在这里就是存着已匹配规则的栈。</p>
<p>CFG 对应的自动机为 PDA(下推自动机)。</p>
<p>RG 的规定严格，对应的好处是它对应的自动机非常简单，所以可以用非常高效且简单的方式来实现。</p>
<h4 id="上下文相关文法"><a class="header" href="#上下文相关文法">上下文相关文法</a></h4>
<p>CSG 在 CFG的基础上进一步放宽限制。</p>
<p>产生式的左手边也可以有终结符和非终结符。左手边的终结符就是“上下文”的来源。也就是说匹配的时候不能光看当前匹配到哪里了，还得看当前位置的左右到底有啥（也就是上下文是啥），上下文在这条规则应用的时候并不会被消耗掉，只是“看看”。</p>
<p>CSG 的再上一层是 PSG，phrase structure grammar。</p>
<p>基本上就是CSG的限制全部取消掉。</p>
<p>左右两边都可以有任意多个、任意顺序的终结符和非终结符。</p>
<p>反正不做自然语言处理的话也不会遇到这种文法，所以具体就不说了。</p>
<h3 id="4-为什么有-n-个运算符的优先级就对应-n1-个产生式"><a class="header" href="#4-为什么有-n-个运算符的优先级就对应-n1-个产生式">4. 为什么有 n 个运算符的优先级，就对应 n+1 个产生式？</a></h3>
<p>优先级的处理可以在纯文法层面解决，也可以在parser实现中用别的办法处理掉。</p>
<p>纯文法层面书上介绍的，有多少个优先级就有那么多加1个产生式。</p>
<p>书上介绍的四则运算的文法，会使得加减法离根比较近，乘除法离根比较远。</p>
<p>语法树的形状决定了节点的计算顺序，离根远的节点就会先处理，这样看起来就是乘除法先计算，也就是乘除法的优先级更高。</p>
<p>参考：http://rednaxelafx.iteye.com/blog/492667</p>
<h3 id="5-避免二义性文法的有效原则"><a class="header" href="#5-避免二义性文法的有效原则">5. 避免二义性文法的有效原则？</a></h3>
<p>二义性问题主要是跟 CFG 的特性有关系的。</p>
<p>CFG 的选择结构（&quot;|&quot;）是没有规定顺序或者说优先级的，
同时，多个规则可能会有共同前缀，
这样才会有二义性问题。</p>
<p>PEG 是跟CFG类似的一种东西，语言的表达力上跟CFG相似。
但文法层面没有二义性，因为它的选择结构（&quot;|&quot;）是有顺序或者说有优先级的。</p>
<h3 id="6-避免预测分析器因左递归文法造成的无限循环"><a class="header" href="#6-避免预测分析器因左递归文法造成的无限循环">6. 避免预测分析器因左递归文法造成的无限循环</a></h3>
<p>产生式：</p>
<p>A -&gt; A x | y</p>
<p>语法制导翻译伪代码片段：</p>
<pre><code>void A(){
    switch(lookahead){
        case x:
            A();match(x);break;
        case y:
            match(y):break;
        default:
            report(&quot;syntax error&quot;)
    }
}
</code></pre>
<p>当语句符合 A x 形式时， A() 运算会陷入死循环，可以通过将产生式改为等价的非左递归形式来避免: </p>
<p>B -&gt; y C</p>
<p>C -&gt; x C | ε</p>
<h3 id="7-为什么在右递归的文法中包含了左结合运算符的表达式翻译会比较困难"><a class="header" href="#7-为什么在右递归的文法中包含了左结合运算符的表达式翻译会比较困难">7. 为什么在右递归的文法中，包含了左结合运算符的表达式翻译会比较困难？</a></h3>
<h3 id="8-中间代码生成时的左值和右值问题"><a class="header" href="#8-中间代码生成时的左值和右值问题">8. 中间代码生成时的左值和右值问题。</a></h3>
<p>看了书上 lvalue() 和 rvalue() 的伪代码，感觉可以做左值也可以做右值的都由 lvalue() 处理，而对于右值的处理，要么自己处理掉了，对于可以作为左值的右值则调用 lvalue()。</p>
<p>为什么不直接弄个 value() 就结了？</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="exercises-for-section-22"><a class="header" href="#exercises-for-section-22">Exercises for Section 2.2</a></h1>
<h3 id="221"><a class="header" href="#221">2.2.1</a></h3>
<p>Consider the context-free grammar:</p>
<p>S -&gt; S S + | S S * | a</p>
<ol>
<li>Show how the string <code>aa+a*</code> can be generated by this grammar.</li>
<li>Construct a parse tree for this string.</li>
<li>What language does this grammar generate? Justify your answer.</li>
</ol>
<h4 id="answer-10"><a class="header" href="#answer-10">Answer</a></h4>
<ol>
<li><code>S</code> -&gt; <code>S</code> S * -&gt; <code>S</code> S + S * -&gt; a <code>S</code> + S * -&gt; a a + <code>S</code> * -&gt; a a + a *</li>
<li><img src="ch02/2.2/./assets/2.2.1-2.png" alt="Syntax tree" /></li>
<li>L = {Postfix expression consisting of digits, plus and multiple signs}</li>
</ol>
<h3 id="222"><a class="header" href="#222">2.2.2</a></h3>
<p>What language is generated by the following grammars? In each case justify your answer.</p>
<ol>
<li>S -&gt; 0 S 1 | 0 1</li>
<li>S -&gt; + S S | - S S | a</li>
<li>S -&gt; S ( S ) S | ε</li>
<li>S -&gt; a S b S | b S a S | ε</li>
<li>S -&gt; a | S + S | S S | S * | ( S )</li>
</ol>
<h4 id="answer-11"><a class="header" href="#answer-11">Answer</a></h4>
<ol>
<li>L = {0<sup>n</sup>1<sup>n</sup> | n&gt;=1}</li>
<li>L = {Prefix expression consisting of plus and minus signs}</li>
<li>L = {Matched brackets of arbitrary arrangement and nesting, includes ε}</li>
<li>L = {String has the same amount of a and b, includes ε}</li>
<li>L = {Regular expressions used to describe regular languages} <a href="http://en.wikipedia.org/wiki/Regular_expression">refer to wiki</a></li>
</ol>
<h3 id="223"><a class="header" href="#223">2.2.3</a></h3>
<p>Which of the grammars in Exercise 2.2.2 are ambiguous?</p>
<h4 id="answer-12"><a class="header" href="#answer-12">Answer</a></h4>
<ol>
<li>
<p>No</p>
</li>
<li>
<p>No</p>
</li>
<li>
<p>Yes</p>
<p><img src="ch02/2.2/./assets/2.2.3-3.png" alt="ambiguous parse tree" /></p>
</li>
<li>
<p>Yes</p>
<p><img src="ch02/2.2/./assets/2.2.3-4.png" alt="ambiguous parse tree" /></p>
</li>
<li>
<p>Yes</p>
<p><img src="ch02/2.2/./assets/2.2.3-5.png" alt="ambiguous parse tree" /></p>
</li>
</ol>
<h3 id="224"><a class="header" href="#224">2.2.4</a></h3>
<p>Construct unambiguous context-free grammars for each of
the following languages. In each case show that your grammar is correct.</p>
<ol>
<li>Arithmetic expressions in postfix notation.</li>
<li>Left-associative lists of identifiers separated by commas.</li>
<li>Right-associative lists of identifiers separated by commas.</li>
<li>Arithmetic expressions of integers and identifiers with the four binary operators +, -, *, /.</li>
<li>Add unary plus and minus to the arithmetic operators of 4.</li>
</ol>
<h4 id="answer-13"><a class="header" href="#answer-13">Answer</a></h4>
<pre><code>1. E -&gt; E E op | num

2. list -&gt; list , id | id

3. list -&gt; id , list | id

4. expr -&gt; expr + term | expr - term | term
   term -&gt; term * factor | term / factor | factor
   factor -&gt; id | num | (expr)

5. expr -&gt; expr + term | expr - term | term
   term -&gt; term * unary | term / unary | unary
   unary -&gt; + factor | - factor | factor
   factor - &gt; id | num | (expr)
</code></pre>
<h3 id="225"><a class="header" href="#225">2.2.5</a></h3>
<ol>
<li>
<p>Show that all binary strings generated by the following grammar have values divisible by 3. Hint. Use induction on the number of nodes in a parse tree.</p>
<p>num -&gt; 11 | 1001 | num 0 | num num</p>
</li>
<li>
<p>Does the grammar generate all binary strings with values divisible by 3?</p>
</li>
</ol>
<h4 id="answer-14"><a class="header" href="#answer-14">Answer</a></h4>
<ol>
<li>
<p>Proof</p>
<p>Any string derived from the grammar can be considered to be a sequence consisting of 11 and 1001, where each sequence element is possibly suffixed with a 0.</p>
<p>Let <code>n</code> be the set of positions where <code>11</code> is placed. <code>11</code> is said to be at position <code>i</code> if the first <code>1</code> in <code>11</code> is at position <code>i</code>, where <code>i</code> starts at 0 and
grows from least significant to most significant bit.</p>
<p>Let <code>m</code> be the equivalent set for <code>1001</code>.</p>
<p>The sum of any string produced by the grammar is:</p>
<p>sum</p>
<p>= Σ<sub>n</sub> (2<sup>1</sup> + 2<sup>0</sup>) * 2 <sup>n</sup> + Σ<sub>m</sub> (2<sup>3</sup> + 2<sup>0</sup>) * 2<sup>m</sup></p>
<p>= Σ<sub>n</sub> 3 * 2 <sup>n</sup> + Σ<sub>m</sub> 9 * 2<sup>m</sup></p>
<p>This is clearly divisible by 3.</p>
</li>
<li>
<p>No. Consider the string &quot;10101&quot;, which is divisible by 3, but cannot be
derived from the grammar.</p>
<p>Readers seeking a more formal proof can read about it below:</p>
<p><strong>Proof</strong>:</p>
<p>Every number divisible by 3 can be written in the form <code>3k</code>. We will consider <code>k &gt; 0</code> (though it would be valid to consider <code>k</code> to be an arbitrary integer).</p>
<p>Note that every part of num(11, 1001 and 0) is divisible by 3, if the grammar could generate all the numbers divisible by 3, we can get a production for binary k from num's production:</p>
<pre><code>3k = num   -&gt; 11 | 1001 | num 0 | num num
 k = num/3 -&gt; 01 | 0011 | k 0   | k k
 k         -&gt; 01 | 0011 | k 0   | k k
</code></pre>
<p>It is obvious that any value of <code>k</code> that has more than 2 consecutive bits set to 1 can never be produced. This can be confirmed by the example given in the beginning:</p>
<p>10101 is 3*7, hence, k = 7 = 111 in binary. Because 111 has more than 2
consecutive 1's in binary, the grammar will never produce 21.</p>
</li>
</ol>
<h3 id="226"><a class="header" href="#226">2.2.6</a></h3>
<p>Construct a context-free grammar for roman numerals.</p>
<p><strong>Note:</strong> we just consider a subset of roman numerals which is less than 4k.</p>
<h4 id="answer-15"><a class="header" href="#answer-15">Answer</a></h4>
<p><a href="http://en.wikipedia.org/wiki/Roman_numerals">wikipedia: Roman_numerals</a></p>
<ul>
<li>
<p>via wikipedia, we can categorize the single roman numerals into 4 groups:</p>
<pre><code>I, II, III | I V | V, V I, V II, V III | I X
</code></pre>
<p>then get the production:</p>
<pre><code>digit -&gt; smallDigit | I V | V smallDigit | I X
smallDigit -&gt; I | II | III | ε
</code></pre>
</li>
<li>
<p>and we can find a simple way to map roman to arabic numerals. For example:</p>
<ul>
<li>XII =&gt; X, II =&gt; 10 + 2 =&gt; 12</li>
<li>CXCIX =&gt; C, XC, IX =&gt; 100 + 90 + 9 =&gt; 199</li>
<li>MDCCCLXXX =&gt; M, DCCC, LXXX =&gt; 1000 + 800 + 80 =&gt; 1880</li>
</ul>
</li>
<li>
<p>via the upper two rules, we can derive the production:</p>
<p>romanNum -&gt; thousand hundred ten digit</p>
<p>thousand -&gt; M | MM | MMM | ε</p>
<p>hundred -&gt; smallHundred | C D | D smallHundred | C M</p>
<p>smallHundred -&gt; C | CC | CCC  | ε</p>
<p>ten -&gt; smallTen | X L | L smallTen | X C</p>
<p>smallTen -&gt; X | XX | XXX | ε</p>
<p>digit -&gt; smallDigit | I V | V smallDigit | I X</p>
<p>smallDigit -&gt; I | II | III  | ε</p>
</li>
</ul>
<div style="break-before: page; page-break-before: always;"></div><h1 id="23-exercises-for-section-23"><a class="header" href="#23-exercises-for-section-23">2.3 Exercises for Section 2.3</a></h1>
<h3 id="231"><a class="header" href="#231">2.3.1</a></h3>
<p>Construct a syntax-directed translation scheme that translates arithmetic
expressions from infix notation into prefix notation in which an operator
appears before its operands; e.g. , -xy is the prefix notation for x - y. Give
annotated parse trees for the inputs 9-5+2 and 9-5*2.</p>
<h4 id="answer-16"><a class="header" href="#answer-16">Answer</a></h4>
<p>productions:</p>
<pre><code>expr -&gt; expr + term
      | expr - term
      | term
term -&gt; term * factor
      | term / factor
      | factor
factor -&gt; digit | (expr)
</code></pre>
<p>translation schemes:</p>
<pre><code>expr -&gt; {print(&quot;+&quot;)} expr + term
      | {print(&quot;-&quot;)} expr - term
      | term
term -&gt; {print(&quot;*&quot;)} term * factor
      | {print(&quot;/&quot;)} term / factor
      | factor
factor -&gt; digit {print(digit)}
        | (expr)
</code></pre>
<h3 id="232"><a class="header" href="#232">2.3.2</a></h3>
<p>Construct a syntax-directed translation scheme that translates arithmetic
expressions from postfix notation into infix notation. Give annotated parse
trees for the inputs 95-2* and 952*-.</p>
<h4 id="answer-17"><a class="header" href="#answer-17">Answer</a></h4>
<p>productions:</p>
<pre><code>expr -&gt; expr expr +
      | expr expr -
      | expr expr *
      | expr expr /
      | digit
</code></pre>
<p>translation schemes:</p>
<pre><code>expr -&gt; expr {print(&quot;+&quot;)} expr +
      | expr {print(&quot;-&quot;)} expr -
      | {print(&quot;(&quot;)} expr {print(&quot;)*(&quot;)} expr {print(&quot;)&quot;)} *
      | {print(&quot;(&quot;)} expr {print(&quot;)/(&quot;)} expr {print(&quot;)&quot;)} /
      | digit {print(digit)}
</code></pre>
<h4 id="another-reference-answer"><a class="header" href="#another-reference-answer">Another reference answer</a></h4>
<pre><code>E -&gt; {print(&quot;(&quot;)} E {print(op)} E {print(&quot;)&quot;}} op | digit {print(digit)}
</code></pre>
<h3 id="233"><a class="header" href="#233">2.3.3</a></h3>
<p>Construct a syntax-directed translation scheme that translates integers into
roman numerals.</p>
<h4 id="answer-18"><a class="header" href="#answer-18">Answer</a></h4>
<p>assistant function:</p>
<pre><code>repeat(sign, times) // repeat('a',2) = 'aa'
</code></pre>
<p>translation schemes:</p>
<pre><code>num -&gt; thousand hundred ten digit
       { num.roman = thousand.roman || hundred.roman || ten.roman || digit.roman;
         print(num.roman)}
thousand -&gt; low {thousand.roman = repeat('M', low.v)}
hundred -&gt; low {hundred.roman = repeat('C', low.v)}
         | 4 {hundred.roman = 'CD'}
         | high {hundred.roman = 'D' || repeat('X', high.v - 5)}
         | 9 {hundred.roman = 'CM'}
ten -&gt; low {ten.roman = repeat('X', low.v)}
     | 4 {ten.roman = 'XL'}
     | high {ten.roman = 'L' || repeat('X', high.v - 5)}
     | 9 {ten.roman = 'XC'}
digit -&gt; low {digit.roman = repeat('I', low.v)}
       | 4 {digit.roman = 'IV'}
       | high {digit.roman = 'V' || repeat('I', high.v - 5)}
       | 9 {digit.roman = 'IX'}
low -&gt; 0 {low.v = 0}
     | 1 {low.v = 1}
     | 2 {low.v = 2}
     | 3 {low.v = 3}
high -&gt; 5 {high.v = 5}
      | 6 {high.v = 6}
      | 7 {high.v = 7}
      | 8 {high.v = 8}
</code></pre>
<h3 id="234"><a class="header" href="#234">2.3.4</a></h3>
<p>Construct a syntax-directed translation scheme that trans­ lates roman numerals into integers.</p>
<h4 id="answer-19"><a class="header" href="#answer-19">Answer</a></h4>
<p>productions:</p>
<pre><code>romanNum -&gt; thousand hundred ten digit
thousand -&gt; M | MM | MMM | ε
hundred -&gt; smallHundred | C D | D smallHundred | C M
smallHundred -&gt; C | CC | CCC | ε
ten -&gt; smallTen | X L | L smallTen | X C
smallTen -&gt; X | XX | XXX  | ε
digit -&gt; smallDigit | I V | V smallDigit | I X
smallDigit -&gt; I | II | III | ε
</code></pre>
<p>translation schemes:</p>
<pre><code>romanNum -&gt; thousand hundred ten digit {romanNum.v = thousand.v || hundred.v || ten.v || digit.v; print(romanNun.v)}
thousand -&gt; M {thousand.v = 1}
          | MM {thousand.v = 2}
          | MMM {thousand.v = 3}
          | ε {thousand.v = 0}
hundred -&gt; smallHundred {hundred.v = smallHundred.v}
         | C D {hundred.v = smallHundred.v}
         | D smallHundred {hundred.v = 5 + smallHundred.v}
         | C M {hundred.v = 9}
smallHundred -&gt; C {smallHundred.v = 1}
              | CC {smallHundred.v = 2}
              | CCC {smallHundred.v = 3}
              | ε {hundred.v = 0}
ten -&gt; smallTen {ten.v = smallTen.v}
     | X L  {ten.v = 4}
     | L smallTen  {ten.v = 5 + smallTen.v}
     | X C  {ten.v = 9}
smallTen -&gt; X {smallTen.v = 1}
          | XX {smallTen.v = 2}
          | XXX {smallTen.v = 3}
          | ε {smallTen.v = 0}
digit -&gt; smallDigit {digit.v = smallDigit.v}
       | I V  {digit.v = 4}
       | V smallDigit  {digit.v = 5 + smallDigit.v}
       | I X  {digit.v = 9}
 smallDigit -&gt; I {smallDigit.v = 1}
            | II {smallDigit.v = 2}
            | III {smallDigit.v = 3}
            | ε {smallDigit.v = 0}
</code></pre>
<h3 id="235"><a class="header" href="#235">2.3.5</a></h3>
<p>Construct a syntax-directed translation scheme that translates postfix
arithmetic expressions into equivalent prefix arithmetic expressions.</p>
<h4 id="answer-20"><a class="header" href="#answer-20">Answer</a></h4>
<p>production:</p>
<pre><code>expr -&gt; expr expr op | digit
</code></pre>
<p>translation scheme:</p>
<pre><code>expr -&gt; {print(op)} expr expr op | digit {print(digit)}
</code></pre>
<div style="break-before: page; page-break-before: always;"></div><h2 id="exercises-for-section-24"><a class="header" href="#exercises-for-section-24">Exercises for Section 2.4</a></h2>
<h3 id="241"><a class="header" href="#241">2.4.1</a></h3>
<p>Construct recursive-descent parsers, starting with the following grammars:</p>
<ol>
<li>S -&gt; + S S | - S S | a</li>
<li>S -&gt; S ( S ) S | ε</li>
<li>S -&gt; 0 S 1 | 0 1</li>
</ol>
<h3 id="answer-21"><a class="header" href="#answer-21">Answer</a></h3>
<p>See <a href="ch02/2.4/./2.4.1.1.c">2.4.1.1.c</a>, <a href="ch02/2.4/./2.4.1.2.c">2.4.1.2.c</a>, and <a href="ch02/2.4/./2.4.1.3.c">2.4.1.3.c</a> for real implementations in C.</p>
<p>1） S -&gt; + S S | - S S | a</p>
<pre><code>void S(){
  switch(lookahead){
    case &quot;+&quot;:
      match(&quot;+&quot;); S(); S();
      break;
    case &quot;-&quot;:
      match(&quot;-&quot;); S(); S();
      break;
    case &quot;a&quot;:
      match(&quot;a&quot;);
      break;
    default:
      throw new SyntaxException();
  }
}
void match(Terminal t){
  if(lookahead = t){
    lookahead = nextTerminal();
  }else{
    throw new SyntaxException()
  }
}
</code></pre>
<p>2） S -&gt; S ( S ) S | ε</p>
<pre><code>void S(){
  if(lookahead == &quot;(&quot;){
    match(&quot;(&quot;); S(); match(&quot;)&quot;); S();
  }
}
</code></pre>
<p>3） S -&gt; 0 S 1 | 0 1</p>
<pre><code>void S(){
  switch(lookahead){
    case &quot;0&quot;:
      match(&quot;0&quot;); S(); match(&quot;1&quot;);
      break;
    case &quot;1&quot;:
      // match(epsilon);
      break;
    default:
      throw new SyntaxException();
  }
}
</code></pre>
<div style="break-before: page; page-break-before: always;"></div><h1 id="exercises-for-section-26"><a class="header" href="#exercises-for-section-26">Exercises for Section 2.6</a></h1>
<h3 id="261"><a class="header" href="#261">2.6.1</a></h3>
<p>Extend the lexical analyzer in Section 2.6.5 to remove comments, defined as
follows:</p>
<ol>
<li>A comment begins with // and includes all characters until the end of that line.</li>
<li>A comment begins with /* and includes all characters through the next occurrence of the character sequence */.</li>
</ol>
<h3 id="262"><a class="header" href="#262">2.6.2</a></h3>
<p>Extend the lexical analyzer in Section 2.6.5 to recognize the relational operators &lt;, &lt;=, ==, ! =, &gt;=, &gt;.</p>
<h3 id="263"><a class="header" href="#263">2.6.3</a></h3>
<p>Extend the lexical analyzer in Section 2.6.5 to recognize floating point numbers
such as 2., 3.14, and . 5.</p>
<h3 id="answer-22"><a class="header" href="#answer-22">Answer</a></h3>
<p>Source code: commit 8dd1a9a</p>
<p>Code snippet(src/lexer/Lexer.java)：</p>
<pre><code>public Token scan() throws IOException, SyntaxException{
  for(;;peek = (char)stream.read()){
    if(peek == ' ' || peek == '\t'){
      continue;
    }else if(peek == '\n'){
      line = line + 1;
    }else{
      break;
    }
  }

  // handle comment
  if(peek == '/'){
    peek = (char) stream.read();
    if(peek == '/'){
      // single line comment
      for(;;peek = (char)stream.read()){
        if(peek == '\n'){
          break;
        }
      }
    }else if(peek == '*'){
      // block comment
      char prevPeek = ' ';
      for(;;prevPeek = peek, peek = (char)stream.read()){
        if(prevPeek == '*' &amp;&amp; peek == '/'){
          break;
        }
      }
    }else{
      throw new SyntaxException();
    }
  }

  // handle relation sign
  if(&quot;&lt;=!&gt;&quot;.indexOf(peek) &gt; -1){
    StringBuffer b = new StringBuffer();
    b.append(peek);
    peek = (char)stream.read();
    if(peek == '='){
      b.append(peek);
    }
    return new Rel(b.toString());
  }

  // handle number, no type sensitive
  if(Character.isDigit(peek) || peek == '.'){
    Boolean isDotExist = false;
    StringBuffer b = new StringBuffer();
    do{
      if(peek == '.'){
        isDotExist = true;
      }
      b.append(peek);
      peek = (char)stream.read();
    }while(isDotExist == true ? Character.isDigit(peek) : Character.isDigit(peek) || peek == '.');
    return new Num(new Float(b.toString()));
  }

  // handle word
  if(Character.isLetter(peek)){
    StringBuffer b = new StringBuffer();
    do{
      b.append(peek);
      peek = (char)stream.read();
    }while(Character.isLetterOrDigit(peek));
    String s = b.toString();
    Word w = words.get(s);
    if(w == null){
      w = new Word(Tag.ID, s);
      words.put(s, w);
    }
    return w;
  }

  Token t = new Token(peek);
  peek = ' ';
  return t;
}
</code></pre>
<div style="break-before: page; page-break-before: always;"></div><h1 id="exercises-for-section-28"><a class="header" href="#exercises-for-section-28">Exercises for Section 2.8</a></h1>
<h3 id="281"><a class="header" href="#281">2.8.1</a></h3>
<p>For-statements in C and Java have the form:</p>
<p>for ( exprl ; expr2 ; expr3 ) stmt</p>
<p>The first expression is executed before the loop; it is typically used for
initializing the loop index. The second expression is a test made before each
iteration of the loop; the loop is exited if the expression becomes 0. The loop
itself can be thought of as the statement {stmt expr3 ; }. The third expression
is executed at the end of each iteration; it is typically used to increment the
loop index. The meaning of the for-statement is similar to</p>
<p>expr1 ; while ( expr2 ) {stmt expr3 ; }</p>
<p>Define a class For for for-statements, similar to class If in Fig. 2.43.</p>
<h4 id="answer-23"><a class="header" href="#answer-23">Answer</a></h4>
<pre><code>class For extends Stmt {
  Expr E1;
  Expr E2;
  Expr E3;
  Stmt S;
  public For(Expr expr1, Expr expr2, Expr expr3, Stmt stmt){
    E1 = expr1;
    E2 = expr2;
    E3 = expr3;
    S = stmt;
  }
  public void gen(){
    E1.gen();
    Label start = new Label();
    Label end = new Label();
    emit(&quot;ifFalse &quot; + E2.rvalue().toString() + &quot; goto &quot; + end);
    S.gen();
    E3.gen();
    emit(&quot;goto &quot; + start);
    emit(end + &quot;:&quot;)
  }
}
</code></pre>
<h3 id="282"><a class="header" href="#282">2.8.2</a></h3>
<p>The programming language C does not have a boolean type. Show how a C compiler might translate an if-statement into three-address code.</p>
<h4 id="answer-24"><a class="header" href="#answer-24">Answer</a></h4>
<p>Replace</p>
<pre><code>emit(&quot;ifFalse &quot; + E.rvalue().toString() + &quot; goto &quot; + after);
</code></pre>
<p>with</p>
<pre><code>emit(&quot;ifEqual &quot; + E.rvalue().toString() + &quot; 0 goto &quot; + after);
</code></pre>
<p>or</p>
<pre><code>emit(&quot;ifEqualZero &quot; + E.rvalue().toString() + &quot; goto &quot; + after);
</code></pre>
<div style="break-before: page; page-break-before: always;"></div><h1 id="chapter-3"><a class="header" href="#chapter-3">Chapter 3</a></h1>
<p>Chapter 3: Lexical Analysis</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="第3章要点"><a class="header" href="#第3章要点">第3章要点</a></h1>
<h3 id="1-从-nfadfa-到正则表达式的转换"><a class="header" href="#1-从-nfadfa-到正则表达式的转换">1. 从 NFA、DFA 到正则表达式的转换</a></h3>
<p>http://courses.engr.illinois.edu/cs373/sp2009/lectures/lect_08.pdf</p>
<h3 id="2-kmp-及其扩展算法p87"><a class="header" href="#2-kmp-及其扩展算法p87">2. KMP 及其扩展算法(p87)</a></h3>
<p>参考 matrix 的博文 <a href="http://www.matrix67.com/blog/archives/115">KMP算法详解</a>。文中提供了例子，比较容易理解。</p>
<h3 id="3-字符串处理算法的效率p103"><a class="header" href="#3-字符串处理算法的效率p103">3. 字符串处理算法的效率(p103)</a></h3>
<p>对于每个构造得到的 DFA 状态，我们最多必须构造 4|r| 个新状态</p>
<h3 id="4-dfa-模拟中的时间和空间的权衡p116"><a class="header" href="#4-dfa-模拟中的时间和空间的权衡p116">4. DFA 模拟中的时间和空间的权衡(p116)</a></h3>
<p>图 3-66 表示的算法</p>
<h3 id="5-最小化一个-dfa-的状态数量p115"><a class="header" href="#5-最小化一个-dfa-的状态数量p115">5. 最小化一个 DFA 的状态数量（p115）</a></h3>
<p>注意图 3-64 的第 4 行：“状态 s 和 t 在 a 上的转换都到达 Π 中的同一组”，而不是到达同一个状态。如果通过是否到达同一个状态来判定，那么如果 s 和 t 在 a 上的转换到了两个不同但不能区分的状态时，就会认为 s 和 t 是可区分的。</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="exercises-for-section-31"><a class="header" href="#exercises-for-section-31">Exercises for Section 3.1</a></h1>
<h3 id="311"><a class="header" href="#311">3.1.1</a></h3>
<p>Divide the following C++ program:</p>
<pre><code>float limitedSquare(x){float x;
  /* returns x-squared, nut never more than 100 */
  return (x &lt;= -10.0 || x &gt;= 10.0) ? 100 : x*x;
}
</code></pre>
<p>into appropriate lexemes, using the discussion of Section 3.1.2 as a guide.
Which lexemes should get associated lexical values? What should those values be?</p>
<h4 id="answer-25"><a class="header" href="#answer-25">Answer</a></h4>
<pre><code>&lt;float&gt; &lt;id, limitedSquaare&gt; &lt;(&gt; &lt;id, x&gt; &lt;)&gt; &lt;{&gt;
  &lt;float&gt; &lt;id, x&gt;
  &lt;return&gt; &lt;(&gt; &lt;id, x&gt; &lt;op,&quot;&lt;=&quot;&gt; &lt;num, -10.0&gt; &lt;op, &quot;||&quot;&gt; &lt;id, x&gt; &lt;op, &quot;&gt;=&quot;&gt; &lt;num, 10.0&gt; &lt;)&gt; &lt;op, &quot;?&quot;&gt; &lt;num, 100&gt; &lt;op, &quot;:&quot;&gt; &lt;id, x&gt; &lt;op, &quot;*&quot;&gt; &lt;id, x&gt;
&lt;}&gt;
</code></pre>
<h3 id="312"><a class="header" href="#312">3.1.2</a></h3>
<p>Tagged languages like HTML or XML are different from conventional programming
languages in that the punctuation (tags) are either very numerous (as in HTML)
or a user-definable set (as in XML). Further, tags can often have parameters.
Suggest how to divide the following HTML document:</p>
<pre><code>Here is a photo of &lt;b&gt;my house&lt;/b&gt;;
&lt;p&gt;&lt;img src=&quot;house.gif&quot;/&gt;&lt;br/&gt;
see &lt;a href=&quot;morePix.html&quot;&gt;More Picture&lt;/a&gt; if you
liked that one.&lt;/p&gt;
</code></pre>
<p>into appropriate lexemes. Which lexemes should get associated lexical values, and what should those values be?</p>
<h4 id="answer-26"><a class="header" href="#answer-26">Answer</a></h4>
<pre><code>&lt;text, &quot;Here is a photo of&quot;&gt; &lt;nodestart, b&gt; &lt;text, &quot;my house&quot;&gt; &lt;nodeend, b&gt;
&lt;nodestart, p&gt; &lt;selfendnode, img&gt; &lt;selfendnode, br&gt;
&lt;text, &quot;see&quot;&gt; &lt;nodestart, a&gt; &lt;text, &quot;More Picture&quot;&gt; &lt;nodeend, a&gt;
&lt;text, &quot;if you liked that one.&quot;&gt; &lt;nodeend, p&gt;
</code></pre>
<div style="break-before: page; page-break-before: always;"></div><h1 id="exercises-for-section-33"><a class="header" href="#exercises-for-section-33">Exercises for Section 3.3</a></h1>
<h3 id="331"><a class="header" href="#331">3.3.1</a></h3>
<p>Consult the language reference manuals to determine</p>
<ol>
<li>the sets of characters that form the input alphabet (excluding those that may only appear in character strings or comments)</li>
<li>the lexical form of numerical constants, and</li>
<li>the lexical form of identifiers, </li>
</ol>
<p>for each of the following languages:</p>
<ol>
<li>C</li>
<li>C++</li>
<li>C#</li>
<li>Fortran</li>
<li>Java</li>
<li>Lisp</li>
<li>SQL</li>
</ol>
<h3 id="332"><a class="header" href="#332">3.3.2</a></h3>
<p>Describe the languages denoted by the following regular expressions:</p>
<ol>
<li>a(a|b)*a</li>
<li>((ε|a)b*)*</li>
<li>(a|b)*a(a|b)(a|b)</li>
<li>a*ba*ba*ba*</li>
<li>!! (aa|bb)*((ab|ba)(aa|bb)*(ab|ba)(aa|bb)*)*</li>
</ol>
<h4 id="answer-27"><a class="header" href="#answer-27">Answer</a></h4>
<ol>
<li>String of a's and b's that start and end with a.</li>
<li>String of a's and b's.</li>
<li>String of a's and b's that the character third from the last is a.</li>
<li>String of a's and b's that only contains three b.</li>
<li>String of a's and b's that has a even number of a and b.</li>
</ol>
<h3 id="333"><a class="header" href="#333">3.3.3</a></h3>
<p>In a string of length n, how many of the following are there?</p>
<ol>
<li>Prefixes.</li>
<li>Suffixes.</li>
<li>Proper prefixes.</li>
<li>! Substrings.</li>
<li>! Subsequences.</li>
</ol>
<h4 id="answer-28"><a class="header" href="#answer-28">Answer</a></h4>
<ol>
<li>n + 1</li>
<li>n + 1</li>
<li>n - 1</li>
<li>C(n+1,2) + 1 (need to count epsilon in)</li>
<li>Σ(i=0,n) C(n, i)</li>
</ol>
<h3 id="334"><a class="header" href="#334">3.3.4</a></h3>
<p>Most languages are case sensitive, so keywords can be written only one way, and the regular expressions describing their lexeme is very simple. However, some languages, like SQL, are case insensitive, so a keyword can be written either in lowercase or in uppercase, or in any mixture of cases. Thus, the SQL keyword SELECT can also be written select, Select, or sElEcT, for instance. Show how to write a regular expression for a keyword in a case­ insensitive language. Illustrate the idea by writing the expression for &quot;select&quot; in SQL.</p>
<h4 id="answer-29"><a class="header" href="#answer-29">Answer</a></h4>
<pre><code>select -&gt; [Ss][Ee][Ll][Ee][Cc][Tt]
</code></pre>
<h3 id="335"><a class="header" href="#335">3.3.5</a></h3>
<p>！Write regular definitions for the following languages:</p>
<ol>
<li>All strings of lowercase letters that contain the five vowels in order.</li>
<li>All strings of lowercase letters in which the letters are in ascending lexicographic order.</li>
<li>Comments, consisting of a string surrounded by /* and */, without an intervening */, unless it is inside double-quotes (&quot;)</li>
<li>!! All strings of digits with no repeated digits. Hint: Try this problem first with a few digits, such as {O, 1, 2}.</li>
<li>!! All strings of digits with at most one repeated digit.</li>
<li>!! All strings of a's and b's with an even number of a's and an odd number
of b's.</li>
<li>The set of Chess moves,in the informal notation,such as p-k4 or kbp*qn.</li>
<li>!! All strings of a's and b's that do not contain the substring abb.</li>
<li>All strings of a's and b's that do not contain the subsequence abb.</li>
</ol>
<h4 id="answer-30"><a class="header" href="#answer-30">Answer</a></h4>
<p>1、</p>
<pre><code>want -&gt; other* a (other|a)* e (other|e)* i (other|i)* o (other|o)* u (other|u)*
other -&gt; [bcdfghjklmnpqrstvwxyz]
</code></pre>
<p>2、</p>
<pre><code>a* b* ... z*
</code></pre>
<p>3、</p>
<pre><code>\/\*([^*&quot;]*|&quot;.*&quot;|\*+[^/])*\*\/
</code></pre>
<p>4、</p>
<pre><code>want -&gt; 0|A?0?1(A0?1|01)*A?0?|A0?
A -&gt; 0?2(02)*
</code></pre>
<p>Steps:</p>
<p>step1. NFA</p>
<p><img src="ch03/3.3/./assets/3.3.5-4.gif" alt="Transition diagram" /></p>
<p>step2. GNFA</p>
<p><img src="ch03/3.3/./assets/3.3.5-4-1.gif" alt="GNFA" /></p>
<p>step3. Remove node 0 and simplify</p>
<p><img src="ch03/3.3/./assets/3.3.5-4-2.gif" alt="Remove node 0 and simplify" /></p>
<p>step4. Remove node 2 and simplify</p>
<p><img src="ch03/3.3/./assets/3.3.5-4-3.gif" alt="Remove node 2 and simplify" /></p>
<p>step5. Remove node 1 and simplify</p>
<p><img src="ch03/3.3/./assets/3.3.5-4-4.gif" alt="Remove node 1 and simplify" /></p>
<p>6、</p>
<pre><code>want -&gt; (FE*G|(aa)*b)(E|FE*G)
E -&gt; b(aa)*b
F -&gt; a(aa)*b
G -&gt; b(aa)*ab|a
F -&gt; ba(aa)*b
</code></pre>
<p>Steps:</p>
<p>step1. Transition diagram</p>
<p><img src="ch03/3.3/./assets/3.3.5-5.gif" alt="转换图" /></p>
<p>step2. GNFA</p>
<p><img src="ch03/3.3/./assets/3.3.5-5-1.gif" alt="GNFA" /></p>
<p>step3. Remove node A and simplify</p>
<p><img src="ch03/3.3/./assets/3.3.5-5-2.gif" alt="Remove node A and simplify" /></p>
<p>step4. Remove node D and simplify</p>
<p><img src="ch03/3.3/./assets/3.3.5-5-3.gif" alt="Remove node D and simplify" /></p>
<p>step5. Remove node C and simplify</p>
<p><img src="ch03/3.3/./assets/3.3.5-5-4.gif" alt="Remove node C and simplify" /></p>
<p>8、</p>
<pre><code>b*(a+b?)*
</code></pre>
<p>9、</p>
<pre><code>b* | b*a+ | b*a+ba*
</code></pre>
<h3 id="336"><a class="header" href="#336">3.3.6</a></h3>
<p>Write character classes for the following sets of characters:</p>
<ol>
<li>The first ten letters (up to &quot;j&quot;) in either upper or lower case.</li>
<li>The lowercase consonants.</li>
<li>The &quot;digits&quot; in a hexadecimal number (choose either upper or lower case for the &quot;digits&quot; above 9).</li>
<li>The characters that can appear at the end of alegitimate English sentence (e.g. , exclamation point) .</li>
</ol>
<h4 id="answer-31"><a class="header" href="#answer-31">Answer</a></h4>
<ol>
<li>[A-Ja-j]</li>
<li>[bcdfghjklmnpqrstvwxzy]</li>
<li>[0-9a-f]</li>
<li>[.?!]</li>
</ol>
<h3 id="337"><a class="header" href="#337">3.3.7</a></h3>
<p>Note that these regular expressions give all of the following symbols (operator characters) a special meaning:</p>
<pre><code>\ &quot; . ^ $ [ ] * + ? { } | /
</code></pre>
<p>Their special meaning must be turned off if they are needed to represent
themselves in a character string. We can do so by quoting the character within a
string of length one or more; e.g., the regular expression &quot;**&quot; matches the
string ** . We can also get the literal meaning of an operator character by
preceding it by a backslash. Thus, the regular expression \*\* also matches
the string **. Write a regular expression that matches the string &quot;\.</p>
<h4 id="answer-32"><a class="header" href="#answer-32">Answer</a></h4>
<pre><code>\&quot;\\
</code></pre>
<h3 id="339-"><a class="header" href="#339-">3.3.9 !</a></h3>
<p>The regular expression r{m, n} matches from m to n occurrences of the pattern r.
For example, a [ 1 , 5] matches a string of one to five a's. Show that for every
regular expression containing repetition operators of this form, there is an
equivalent regular expression without repetition operators.</p>
<h4 id="answer-33"><a class="header" href="#answer-33">Answer</a></h4>
<p>r{m,n} is equals to r.(m).r | r.(m + 1).r | ... | r.(n).r</p>
<h3 id="3310-"><a class="header" href="#3310-">3.3.10 !</a></h3>
<p>The operator ^ matches the left end of a line, and $ matches the right end of a
line. The operator ^ is also used to introduce complemented character classes,
but the context always makes it clear which meaning is intended. For example,
^<sup class="footnote-reference"><a href="#aeiou">1</a></sup>*$ matches any complete line that does not contain a lowercase vowel.</p>
<ol>
<li>How do you tell which meaning of ^ is intended?</li>
<li>Can you always replace a regular expression using the ^ and $ operators by an equivalent expression that does not use either of these operators?</li>
</ol>
<h4 id="answer-34"><a class="header" href="#answer-34">Answer</a></h4>
<ol>
<li>if ^ is in a pair of brakets, and it is the first letter, it means complemented classes, or it means the left end of a line.</li>
</ol>
<div style="break-before: page; page-break-before: always;"></div><h1 id="34-节的练习"><a class="header" href="#34-节的练习">3.4 节的练习</a></h1>
<h3 id="341"><a class="header" href="#341">3.4.1</a></h3>
<p>给出识别练习 3.3.2 中各个正则表达式所描述的语言状态转换图。</p>
<h4 id="解答"><a class="header" href="#解答">解答</a></h4>
<p>解答步骤：NFA -&gt; DFA -&gt; 最少状态的 DFA（状态转换图）</p>
<ol>
<li>a(a|b)*a</li>
</ol>
<p>NFA:</p>
<p><img src="ch03/3.4/./assets/3.4.1-1-nfa.gif" alt="3 4 1-1-nfa" /></p>
<p>DFA:
转换表：</p>
<table>
<thead>
<tr>
<th>NFA</th>
<th>DFA</th>
<th>a</th>
<th>b</th>
</tr>
</thead>
<tbody>
<tr>
<td>{0}</td>
<td>A</td>
<td>B</td>
<td></td>
</tr>
<tr>
<td>{1,2,3,5,8}</td>
<td>B</td>
<td>C</td>
<td>D</td>
</tr>
<tr>
<td>{2,3,4,5,7,8,<b>9</b>}</td>
<td><b>C</b></td>
<td>C</td>
<td>D</td>
</tr>
<tr>
<td>{2,3,5,6,7,8}</td>
<td>D</td>
<td>C</td>
<td>D</td>
</tr>
</tbody>
</table>
<p>转移图：
<img src="ch03/3.4/./assets/3.4.1-1-dfa.gif" alt="3 4 1-1-dfa" /></p>
<p>​    最少状态的 DFA(状态转换图):</p>
<blockquote>
<p>合并不可区分的状态 B 和 D</p>
</blockquote>
<p><img src="ch03/3.4/./assets/3.4.1-1.gif" alt="3 4 1-1" /></p>
<ol start="2">
<li>
<p>((ε|a)b*)*</p>
<p>直接给出最小化DFA：</p>
<p><img src="ch03/3.4/./assets/3.4.1-2.gif" alt="3 4 1-2" /></p>
</li>
<li>
<p>(a|b)*a(a|b)(a|b)</p>
</li>
</ol>
<p>NFA:</p>
<p><img src="ch03/3.4/./assets/3.4.1-3-nfa.gif" alt="3 4 1-3-nfa" /></p>
<p>DFA:
转换表：</p>
<table>
<thead>
<tr>
<th>NFA</th>
<th>DFA</th>
<th>a</th>
<th>b</th>
</tr>
</thead>
<tbody>
<tr>
<td>{0,1,2,4,7}</td>
<td>A</td>
<td>B</td>
<td>C</td>
</tr>
<tr>
<td>{1,2,3,4,6,7,8,9,11}</td>
<td>B</td>
<td>D</td>
<td>E</td>
</tr>
<tr>
<td>{1,2,4,5,6,7}</td>
<td>C</td>
<td>B</td>
<td>C</td>
</tr>
<tr>
<td>{1,2,3,4,6,7,8,9,10,11,13,14,16}</td>
<td>D</td>
<td><b>F</b></td>
<td><b>G</b></td>
</tr>
<tr>
<td>{1,2,4,5,6,7,12,13,14,16}</td>
<td>E</td>
<td><b>H</b></td>
<td><b>I</b></td>
</tr>
<tr>
<td>{1,2,3,4,6,7,8,9,10,11,13,14,15,16,<b>18</b>}</td>
<td><b>F</b></td>
<td><b>F</b></td>
<td><b>G</b></td>
</tr>
<tr>
<td>{1,2,4,5,6,7,12,13,14,16,17,<b>18</b>}</td>
<td><b>G</b></td>
<td><b>H</b></td>
<td><b>I</b></td>
</tr>
<tr>
<td>{1,2,3,4,6,7,8,9,11,15,<b>18</b>}</td>
<td><b>H</b></td>
<td>D</td>
<td>E</td>
</tr>
<tr>
<td>{1,2,4,5,6,7,17,<b>18</b>}</td>
<td><b>I</b></td>
<td>B</td>
<td>C</td>
</tr>
</tbody>
</table>
<p>​	最少状态的 DFA(状态转换图):</p>
<blockquote>
<p>合并不可区分的状态 A 和 C</p>
</blockquote>
<p><img src="ch03/3.4/./assets/3.4.1-3.gif" alt="3 4 1-3" /></p>
<p>​<br />
4. a*ba*ba*ba*</p>
<pre><code>直接给出最小化DFA：

![3 4 1-4](./assets/3.4.1-4.gif)
</code></pre>
<h3 id="342"><a class="header" href="#342">3.4.2</a></h3>
<p>给出识别练习 3.3.5 中各个正则表达式所描述语言的状态转换图。</p>
<h3 id="343"><a class="header" href="#343">3.4.3</a></h3>
<p>构造下列串的失效函数。</p>
<ol>
<li>abababaab</li>
<li>aaaaaa</li>
<li>abbaabb</li>
</ol>
<h4 id="解答-1"><a class="header" href="#解答-1">解答</a></h4>
<p>代码如下：</p>
<pre><code class="language-javascript">module.exports = failureFunction

function failureFunction(str) {
    var failure = [0]
    var j = 0
    for (var i = 1; i &lt; str.length; i++) {
        while(j &gt; 0 &amp;&amp; str[j] != str[i]) {
            j = failure[j-1]
        }
        if(str[j] == str[i]){
            j++
        }
        failure[i] = j
    }
    return failure
}

</code></pre>
<ol>
<li>[ 0, 0, 1, 2, 3, 4, 5, 1, 2 ]</li>
<li>[ 0, 1, 2, 3, 4, 5 ]</li>
<li>[ 0, 0, 0, 1, 1, 2, 3 ]</li>
</ol>
<h3 id="344-"><a class="header" href="#344-">3.4.4 ！</a></h3>
<p>对 s 进行归纳，证明图 3-19 的算法正确地计算出了失效函数。</p>
<p><strong>图 3-19：计算关键字 b_1b_2…b_n 的失效函数</strong></p>
<pre><code>01  t = 0;
02  f(1) = 0;
03  for (s = 1; s &lt; n; s ++){
04      while( t &gt; 0 &amp;&amp; b_s+1 != b_t+1) t = f(t);
05      if(b_s+1 == b_t+1){
06          t = t + 1;
07          f(s + 1) = t;
08      }else{
09          f(s + 1) = 0;
10      }
11  }
</code></pre>
<h4 id="证明"><a class="header" href="#证明">证明</a></h4>
<ol>
<li>已知 f(1) = 0</li>
<li>在第 1 次 for 循环时，计算 f(2) 的值，当第5行代码 b_2 == b_1 成立时，代码进入到第7行得出 f(2) = 1，不成立时，则代码进入第9行得出 f(2) = 0。显然，这次循环正确的计算出了 f(2) 。</li>
<li>假设在第 i-1 次进入循环时，也正确的计算出了 f(i)，也有 f(i) = t (无论 t 是大于 0 还是等于 0)</li>
<li>那么在第 1 次进入循环时，分两种情况进行考虑：
<ol>
<li>
<p>t == 0</p>
<p>这种情况比较简单，直接从第 5 行开始，当 b_i+1 == b_1 时，f(i+1) = 1，否则 f(i+1) = 0</p>
</li>
<li>
<p>t &gt; 0
while 循环会不断缩小 t 值，试图找出最大可能的使得 b_i+1 == b_t+1 成立的 t 值，如果找到了，则进入第 5 行执行，得到 f(i+1) = t+1；或者直到 t == 0 时也没有找到，则跳出循环，这时进入第 5 行执行，过程类似于前一种情况。</p>
</li>
</ol>
</li>
</ol>
<h3 id="345-"><a class="header" href="#345-">3.4.5 ！！</a></h3>
<p>说明图 3-19 中的第 4 行的复制语句 t = f(t) 最多被执行 n 次。进而说明整个算法的时间复杂度是 O(n)，其中 n 是关键字长度。</p>
<h4 id="解答-2"><a class="header" href="#解答-2">解答</a></h4>
<p>详见 matrix 的博文 <a href="http://www.matrix67.com/blog/archives/115">KMP算法详解</a>。</p>
<h3 id="346"><a class="header" href="#346">3.4.6</a></h3>
<p>应用 KMP 算法判断关键字 ababaa 是否为下面字符串的子串：</p>
<ol>
<li>abababaab</li>
<li>abababbaa</li>
</ol>
<h4 id="解答-3"><a class="header" href="#解答-3">解答</a></h4>
<p>代码如下：</p>
<pre><code class="language-javascript">var failureFunction = require('./failure-function')

module.exports = kmp

function kmp(str, search) {
    var failure = failureFunction(search)
    var s = 0
    for (var i = 0; i &lt; str.length; i++) {
        while (s &gt; 0 &amp;&amp; str[i] != search[s]) {
            s = failure[s-1]
        }
        if(str[i] == search[s]){
            s = s + 1
        }
        if(s == search.length){
            return true
        }
    }
    return false
}
</code></pre>
<p>结果：</p>
<ol>
<li>true</li>
<li>false</li>
</ol>
<h3 id="347-"><a class="header" href="#347-">3.4.7 ！！</a></h3>
<p>说明图 3-20 中的算法可以正确的表示输入关键字是否为一个给定字符串的子串。</p>
<p><strong>图 3-20：KMP 算法在 O(m + n) 的时间内检测字符串a_1a_3...a_n 中是否包含单个关键字 b1b2...bn</strong></p>
<pre><code>s = 0;
for(i = 1; i &lt;= m; i ++){
    while(s &gt; 0 &amp;&amp; a_i != b_s+1) s = f(s);
    if(a_i == b_s+1) s = s + 1;
    if(s == n) return &quot;yes&quot;;
}
return &quot;no&quot;;
</code></pre>
<h3 id="348"><a class="header" href="#348">3.4.8</a></h3>
<p>假设已经计算得到函数 f 且他的值存储在一个以 s 为下标的数字中，说明图 3-20 中算法的时间复杂度为 O(m + n)。</p>
<h4 id="解答-4"><a class="header" href="#解答-4">解答</a></h4>
<p>详见 matrix 的博文 <a href="http://www.matrix67.com/blog/archives/115">KMP算法详解</a>。</p>
<h3 id="349"><a class="header" href="#349">3.4.9</a></h3>
<p>Fibonacci 字符串的定义如下：</p>
<ol>
<li>s1 = b</li>
<li>s2 = a</li>
<li>当 k &gt; 2 时， s<sub>k</sub> = s<sub>k-1</sub> s<sub>k-2</sub></li>
</ol>
<p>例如：s<sub>3</sub> = ab, s<sub>4</sub> = aba, s<sub>5</sub> = abaab</p>
<ol>
<li>s<sub>n</sub> 的长度是多少？</li>
<li>构造 s<sub>6</sub> 的失效函数。</li>
<li>构造 s<sub>7</sub> 的失效函数。</li>
<li>！！ 说明任何 s<sub>n</sub> 的失效函数都可以被表示为：f(1) = f(2) = 0，且对于 2 &lt; j &lt;= |s<sub>n</sub>|, f(j) = j - |s<sub>k-1</sub>|，其中 k 是使得 |s<sub>k</sub>| &lt;= j + 1 的最大整数。</li>
<li>！！ 在 KMP 算法中，当我们试图确定关键字 s<sub>k</sub> 是否出现在字符串 s<sub>k+1</sub> 中，最多会连续多少次调用失效函数？</li>
</ol>
<h4 id="解答-5"><a class="header" href="#解答-5">解答</a></h4>
<ol>
<li>
<p>见 <a href="http://zh.wikipedia.org/wiki/%E6%96%90%E6%B3%A2%E9%82%A3%E5%A5%91%E6%95%B0%E5%88%97">维基百科</a></p>
</li>
<li>
<p>s<sub>6</sub> = abaababa</p>
<p>failure = [ 0, 0, 1, 1, 2, 3, 2, 3 ]</p>
</li>
<li>
<p>s<sub>7</sub> = abaababaabaab</p>
<p>failure = [ 0, 0, 1, 1, 2, 3, 2, 3, 4, 5, 6, 4, 5 ]</p>
</li>
</ol>
<div style="break-before: page; page-break-before: always;"></div><h1 id="exercises-for-section-35"><a class="header" href="#exercises-for-section-35">Exercises for Section 3.5</a></h1>
<h3 id="351"><a class="header" href="#351">3.5.1</a></h3>
<p>Describe how to make the following modifications to the Lex
program of Fig. 3.23:</p>
<ol>
<li>Add the keyword while.</li>
<li>Change the comparison operators to be the C operators of that kind.</li>
<li>Allow the underscore ( _ ) as an additional letter.</li>
<li>! Add a new pattern with token STRING. The pattern consists of a double­
quote ( &quot; ) , any string of characters and a final double-quote. However,
if a double-quote appears in the string, it must be escaped by preceding
it with a backslash () , and therefore a backslash in the string must be
represented by two backslashes. The lexical value, which is the string
without the surrounding double-quotes, and with backslashes used to es.,.
cape a character removed. Strings are to be installed in a table of strings.</li>
</ol>
<p>flex source code:</p>
<pre><code>%{
/* definitions of manifest constants */
LT, LE, EQ, NE, GT, GE,
IF, THEN, ELSE, ID, NUMBER, RELOP, WHILE
%}
/* regular definitions */
delim   [ \t\n]
ws      {delim}+

/* Exercise 3.5.1 - c) We can allow the underscore here, but I think it's better in the ID definition. */
letter  [A-Za-z]
digit   [0-9]

/* Exercise 3.5.1 - c) */
id      {letter}({letter}|{digit}|_)*

number  {digit}+(\.{digit}+)?(E[+-]?{digit }+)?
doubleq \&quot;

%%
{ws} {/* no action and no return */}
if   {return (IF); }
while { return (WHILE); /* Exercise 3.5.1 - a) */ }
then {return (THEN); }
else {return (ELSE) ; }
{id} {yylval = (int) installID(); return (ID); }
{doubleq}.*{doubleq} { yylval = (int) installString(); return (STRING); /* Exercise 3.5.1 - d) */}
{number} {yylval = (int) installNum(); return (NUMBER); }
&quot;&lt;&quot; {yylval = LT; return (RELOP); }
&quot;&lt;=&quot; {yylval = LE; return (RELOP);}
&quot;==&quot; {yylval = EQ; return (RELOP); /* Exercise 3.5.1 - b) */ }
&quot;!=&quot; {yylval = NE; return (RELOP ); /* Exercise 3.5.1 - b) */ }
&quot;&gt;&quot; {yylval = GT; return (RELOP); }
&quot;&gt;=&quot; {yylval = GE; return (RELOP); }

%%

int installID() { /* function to install the lexeme, whose first character is pointed to bu yytext,
and whose length is yyleng, into the symbol table and return a pointer thereto */
}

int installNum() { /* similar to installID, but puts numerical constants into a seperate table */ 
}

int installString() {
/* ... */
}

</code></pre>
<h3 id="352"><a class="header" href="#352">3.5.2</a></h3>
<p>Write a Lex program that copies a file, replacing each non­
empty sequence of white space by a single blank</p>
<h3 id="353"><a class="header" href="#353">3.5.3</a></h3>
<p>Write a Lex program that copies a C program, replacing each
instance of the keyword f loat by double.。</p>
<h3 id="354-"><a class="header" href="#354-">3.5.4 ！</a></h3>
<p>Write a Lex program that converts a file to &quot;Pig latin.&quot;
Specifically, assume the file is a sequence of words (groups . of letters) separated
by whitespace. Every time you encounter a word:</p>
<ol>
<li>If the first letter is a consonant, move it to the end of the word and then
add ay!</li>
<li>If the first letter is a vowel, just add ay to the end of the word.</li>
</ol>
<p>All nonletters are copied int act to the output.</p>
<p>flex source code:</p>
<pre><code>%{
%}

delim 	[ \t]
ws 			{delim}+
letter 	[a-zA-Z]
word   	{letter}+

%%
{ws} { printf(&quot;%s&quot;, yytext); }
{word} { 
	if (starts_vowel(yytext)) 
		printf(&quot;%say&quot;, yytext);
	else
		printf(&quot;%s%cay&quot;, yytext+1, yytext[0]);}
. { printf(&quot;%s&quot;, yytext); }
%%

int starts_vowel(char *c){
	switch(c[0]){
		case 'a':
		case 'e':
		case 'i':
		case 'o':
		case 'u':
		case 'A':
		case 'E':
		case 'I':
		case 'O':
		case 'U':
			return 1;
		default:
			return 0;
 	}
}

</code></pre>
<h3 id="355-"><a class="header" href="#355-">3.5.5 ！</a></h3>
<p>In SQL, keywords and identifiers are case-insensitive. Write
a Lex program that recognizes the keywords SELECT, FROM, and WHERE (in any
combination of capital and lower-case letters) , and token ID, which for the
purposes of this exercise you may take to be any sequence of letters and digits,
beginning with a letter. You need not install identifiers in a symbol table, but
tell how the &quot;install&quot; function would differ from that described for case-sensitive
identifiers as in Fig. 3.23.</p>
<p>flex source code:</p>
<pre><code>%{

%}

letter 	[a-zA-Z]
digit 	[0-9]

/* [w-W][h-H][i-I][l-L][e-E] works too. */
while 	(?i:while)

from	(?i:from)
select	(?i:select)
id	{letter}({letter}|{digit})*

%%
{while} 	{ printf(&quot;WHILE KEYWORD&quot;); return (WHILE); }
{from} 		{ printf(&quot;FROM KEYWORD&quot;); return (FROM); }
{select}	{ printf(&quot;SELECT KEYWORD&quot;); return (SELECT); }
{id}		{ printf(&quot;ID&quot;); yytext = lowercase(yytext); yylval = (int) installID(); return (ID); }	
%%


int installID(){
	/* We've to convert the lexeme to lowercase and install it 

	example:
		yytext: foO
		yytext = lowercase(yytext)
		yylval = (int) installID()

		yytext: Strstr
		yytext = lowercase(yytext)
		yylval = (int) installID()
		
		yytext: strstr (already exists in the symbol table)
		yytext = lowercase(yytext)
		yylval = (int) installID()

	*/
}

</code></pre>
<div style="break-before: page; page-break-before: always;"></div><h1 id="36-exercises-for-section-36"><a class="header" href="#36-exercises-for-section-36">3.6 Exercises for Section 3.6</a></h1>
<h3 id="361-"><a class="header" href="#361-">3.6.1 !</a></h3>
<p>Figure 3.19 in the exercises of Section 3.4 computes the failure
function for the KMP algorithm. Show how, given that failure function, we
can construct, from a keyword b1b2...bn an n + 1-state DFA that recognizes
.*b1b2...bn, where the dot stands for &quot;any character.&quot; Moreover, this DFA can
be constructed in O(n) time.</p>
<h4 id="answer-35"><a class="header" href="#answer-35">Answer</a></h4>
<p>Take the string &quot;abbaabb&quot; in exercise 3.4.3-3 as example, the failure function is:</p>
<ul>
<li>n   : 1, 2, 3, 4, 5, 6, 7</li>
<li>f(n): 0, 0, 0, 1, 1, 2, 3</li>
</ul>
<p>The DFA is：</p>
<p><img src="ch03/3.6/./assets/3.6.1.gif" alt="3 6 1" /></p>
<p>Pseudocode of building the DFA：</p>
<pre><code>for (i = 0; i&lt; n; i ++) {
  move[s[i], c] = {
    if ( c == b1b2…bn[i] ) {
      goto s[i+1]
    } else {
      goto s[f(i)]
    }
  }
}
</code></pre>
<p>It is obviously that with the known f(n), this DFA can be constructed in O(n) time.</p>
<h3 id="362"><a class="header" href="#362">3.6.2</a></h3>
<p>Design finite automata (deterministic or nondeterministic)
for each of the languages of Exercise 3.3.5.</p>
<h3 id="363"><a class="header" href="#363">3.6.3</a></h3>
<p>For the NFA of Fig. 3.29, indicate all the paths labeled aabb.
Does the NFA accept aabb?</p>
<h4 id="answer-36"><a class="header" href="#answer-36">Answer</a></h4>
<ul>
<li>(0) -a-&gt; (1) -a-&gt; (2) -b-&gt; (2) -b-&gt; ((3))</li>
<li>(0) -a-&gt; (0) -a-&gt; (0) -b-&gt; (0) -b-&gt; (0)</li>
<li>(0) -a-&gt; (0) -a-&gt; (1) -b-&gt; (1) -b-&gt; (1)</li>
<li>(0) -a-&gt; (1) -a-&gt; (1) -b-&gt; (1) -b-&gt; (1)</li>
<li>(0) -a-&gt; (1) -a-&gt; (2) -b-&gt; (2) -b-&gt; (2)</li>
<li>(0) -a-&gt; (1) -a-&gt; (2) -b-&gt; (2) -ε-&gt; (0) -b-&gt; (0)</li>
<li>(0) -a-&gt; (1) -a-&gt; (2) -ε-&gt; (0) -b-&gt; (0) -b-&gt; (0)</li>
</ul>
<p>This NFA accepts &quot;aabb&quot;</p>
<h3 id="364"><a class="header" href="#364">3.6.4</a></h3>
<p>Repeat Exercise 3.6.3 for the NFA of Fig. 3.30.</p>
<h3 id="365"><a class="header" href="#365">3.6.5</a></h3>
<p>Give the transition tables for the NFA of: </p>
<ol>
<li>Exercise 3.6.3.</li>
<li>Exercise 3.6.4.</li>
<li>Figure 3.26.</li>
</ol>
<h4 id="answer-37"><a class="header" href="#answer-37">Answer</a></h4>
<p><strong>Table 1</strong></p>
<table>
	<thead>
		<tr>
			<th>state</th>
			<th>a</th>
			<th>b</th>
			<th>ε</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>0</td>
			<td>{0,1}</td>
			<td>{0}</td>
			<td>∅</td>
		</tr>
		<tr>
			<td>1</td>
			<td>{1,2}</td>
			<td>{1}</td>
			<td>∅</td>
		</tr>
		<tr>
			<td>2</td>
			<td>{2}</td>
			<td>{2,3}</td>
			<td>{0}</td>
		</tr>
		<tr>
			<td>3</td>
			<td>∅</td>
			<td>∅</td>
			<td>∅</td>
		</tr>
	</tbody>
</table>
<p><strong>Table 2</strong></p>
<table>
	<thead>
		<tr>
			<th>state</th>
			<th>a</th>
			<th>b</th>
			<th>ε</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>0</td>
			<td>{1}</td>
			<td>∅</td>
			<td>{3}</td>
		</tr>
		<tr>
			<td>1</td>
			<td>∅</td>
			<td>{2}</td>
			<td>{0}</td>
		</tr>
		<tr>
			<td>2</td>
			<td>∅</td>
			<td>{3}</td>
			<td>{1}</td>
		</tr>
		<tr>
			<td>3</td>
			<td>{0}</td>
			<td>∅</td>
			<td>{2}</td>
		</tr>
	</tbody>
</table>
<p><strong>Table 3</strong></p>
<table>
	<thead>
		<tr>
			<th>state</th>
			<th>a</th>
			<th>b</th>
			<th>ε</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>0</td>
			<td>∅</td>
			<td>∅</td>
			<td>{1,2}</td>
		</tr>
		<tr>
			<td>1</td>
			<td>{2}</td>
			<td>∅</td>
			<td>∅</td>
		</tr>
		<tr>
			<td>2</td>
			<td>{2}</td>
			<td>∅</td>
			<td>∅</td>
		</tr>
		<tr>
			<td>3</td>
			<td>∅</td>
			<td>{4}</td>
			<td>∅</td>
		</tr>
		<tr>
			<td>4</td>
			<td>∅</td>
			<td>{4}</td>
			<td>∅</td>
		</tr>
	</tbody>
</table><div style="break-before: page; page-break-before: always;"></div><h1 id="exercises-for-section-37"><a class="header" href="#exercises-for-section-37">Exercises for Section 3.7</a></h1>
<h3 id="371"><a class="header" href="#371">3.7.1</a></h3>
<p>Convert to DFA's the NFA's of:</p>
<ol>
<li>Fig. 3.26.</li>
<li>Fig. 3.29.</li>
<li>Fig. 3.30.</li>
</ol>
<h4 id="answer-38"><a class="header" href="#answer-38">Answer</a></h4>
<p>1、</p>
<p><strong>Transition table</strong></p>
<table>
	<thead>
		<tr>
			<th>NFA State</th>
			<th>DFA State</th>
			<th>a</th>
			<th>b</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>{0,1,3}</td>
			<td>A</td>
			<td>B</td>
			<td>C</td>
		</tr>
		<tr>
			<td>{2}</td>
			<td>B</td>
			<td>B</td>
			<td>∅</td>
		</tr>
		<tr>
			<td>{4}</td>
			<td>C</td>
			<td>∅</td>
			<td>C</td>
		</tr>
	</tbody>
</table>
<p><strong>DFA</strong></p>
<p><img src="ch03/3.7/./assets/3.7.1-1.gif" alt="3 7 1-1" /></p>
<p>2、</p>
<p><strong>Transition table</strong></p>
<table>
	<thead>
		<tr>
			<th>NFA State</th>
			<th>DFA State</th>
			<th>a</th>
			<th>b</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>{0}</td>
			<td>A</td>
			<td>B</td>
			<td>A</td>
		</tr>
		<tr>
			<td>{0,1}</td>
			<td>B</td>
			<td>C</td>
			<td>B</td>
		</tr>
		<tr>
			<td>{0,1,2}</td>
			<td>C</td>
			<td>C</td>
			<td>D</td>
		</tr>
		<tr>
			<td>{0,2,3}</td>
			<td>D</td>
			<td>C</td>
			<td>D</td>
		</tr>
	</tbody>
</table>
<p><strong>DFA</strong></p>
<p><img src="ch03/3.7/./assets/3.7.1-2.gif" alt="3 7 1-2" /></p>
<p>3、</p>
<p><strong>Transition table</strong></p>
<table>
	<thead>
		<tr>
			<th>NFA State</th>
			<th>DFA State</th>
			<th>a</th>
			<th>b</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>{0,1,2,3}</td>
			<td>A</td>
			<td>A</td>
			<td>A</td>
		</tr>
	</tbody>
</table>
<p><strong>DFA</strong></p>
<p><img src="ch03/3.7/./assets/3.7.1-3.gif" alt="3 7 1-3" /></p>
<h3 id="372"><a class="header" href="#372">3.7.2</a></h3>
<p>use Algorithm 3.22 to simulate the NFA's:</p>
<ol>
<li>Fig. 3.29.</li>
<li>Fig. 3.30.</li>
</ol>
<p>on input aabb.</p>
<h4 id="answer-39"><a class="header" href="#answer-39">Answer</a></h4>
<ol>
<li>-start-&gt;{0}-a-&gt;{0,1}-a-&gt;{0,1,2}-b-&gt;{0,2,3}-b-&gt;{0,2,3}</li>
<li>-start-&gt;{0,1,2,3}-a-&gt;{0,1,2,3}-a-&gt;{0,1,2,3}-b-&gt;{0,1,2,3}-b-&gt;{0,1,2,3}</li>
</ol>
<h3 id="373"><a class="header" href="#373">3.7.3</a></h3>
<p>Convert the following regular expressions to deterministic finite automata, using algorithms 3.23 and 3.20:</p>
<ol>
<li>(a|b)*</li>
<li>(a*|b*)*</li>
<li>((ε|a)|b*)*</li>
<li>(a|b)*abb(a|b)*</li>
</ol>
<h4 id="answer-40"><a class="header" href="#answer-40">Answer</a></h4>
<p>1、</p>
<p><strong>NFA</strong></p>
<p><img src="ch03/3.7/./assets/3.7.3-1-nfa.gif" alt="3 7 3-1-nfa" /></p>
<p><strong>Transition table</strong></p>
<table>
	<thead>
		<tr>
			<th>NFA State</th>
			<th>DFA State</th>
			<th>a</th>
			<th>b</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>{0,1,2,3,7}</td>
			<td>A</td>
			<td>B</td>
			<td>C</td>
		</tr>
		<tr>
			<td>{1,2,3,4,6,7}</td>
			<td>B</td>
			<td>B</td>
			<td>C</td>
		</tr>
		<tr>
			<td>{1,2,3,5,6,7}</td>
			<td>C</td>
			<td>B</td>
			<td>C</td>
		</tr>
	</tbody>
</table>
<p><strong>DFA</strong></p>
<p><img src="ch03/3.7/./assets/3.7.3-1-dfa.gif" alt="3 7 3-1-dfa" /></p>
<p>2、</p>
<p><strong>NFA</strong></p>
<p><img src="ch03/3.7/./assets/3.7.3-2-nfa.gif" alt="3 7 3-2-nfa" /></p>
<p><strong>Transition table</strong></p>
<table>
	<thead>
		<tr>
			<th>NFA State</th>
			<th>DFA State</th>
			<th>a</th>
			<th>b</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>{0,1,2,3,4,5,8,9,10,11}</td>
			<td>A</td>
			<td>B</td>
			<td>C</td>
		</tr>
		<tr>
			<td>{1,2,3,4,5,6,8,9,10,11}</td>
			<td>B</td>
			<td>B</td>
			<td>C</td>
		</tr>
		<tr>
			<td>{1,2,3,4,5,7,8,9,10,11}</td>
			<td>C</td>
			<td>B</td>
			<td>C</td>
		</tr>
	</tbody>
</table>
**DFA**
<p><img src="ch03/3.7/./assets/3.7.3-2-dfa.gif" alt="3 7 3-2-dfa" /></p>
<p>3、</p>
<p><strong>NFA</strong></p>
<p><img src="ch03/3.7/./assets/3.7.3-3-nfa.gif" alt="3 7 3-3-nfa" /></p>
<p><strong>Transition table</strong></p>
<table>
	<thead>
		<tr>
			<th>NFA State</th>
			<th>DFA State</th>
			<th>a</th>
			<th>b</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>{0,1,2,3,4,6,7,9,10}</td>
			<td>A</td>
			<td>B</td>
			<td>C</td>
		</tr>
		<tr>
			<td>{1,2,3,4,5,6,7,9,10}</td>
			<td>B</td>
			<td>B</td>
			<td>C</td>
		</tr>
		<tr>
			<td>{1,2,3,4,6,7,8,9,10}</td>
			<td>C</td>
			<td>B</td>
			<td>C</td>
		</tr>
	</tbody>
</table>
<p><strong>DFA</strong></p>
<p><img src="ch03/3.7/./assets/3.7.3-3-dfa.gif" alt="3 7 3-3-dfa" /></p>
<p>4、</p>
<p><strong>NFA</strong></p>
<p><img src="ch03/3.7/./assets/3.7.3-4-nfa.gif" alt="3 7 3-4-nfa" /></p>
<p><strong>Transition table</strong></p>
<table>
	<thead>
		<tr>
			<th>NFA State</th>
			<th>DFA State</th>
			<th>a</th>
			<th>b</th>
		</tr>
	</thead>
	<tbody>
		<tr>
			<td>{0,1,2,4,7}</td>
			<td>A</td>
			<td>B</td>
			<td>C</td>
		</tr>
		<tr>
			<td>{1,2,3,4,6,7,8}</td>
			<td>B</td>
			<td>B</td>
			<td>D</td>
		</tr>
		<tr>
			<td>{1,2,4,5,6,7}</td>
			<td>C</td>
			<td>B</td>
			<td>C</td>
		</tr>
		<tr>
			<td>{1,2,4,5,6,7,9}</td>
			<td>D</td>
			<td>B</td>
			<td>E</td>
		</tr>
		<tr>
			<td>{1,2,4,5,6,7,10,11,12,14,17}</td>
			<td>E</td>
			<td>F</td>
			<td>G</td>
		</tr>
		<tr>
			<td>{1,2,3,4,6,7,8,11,12,13,14,16,17}</td>
			<td>F</td>
			<td>F</td>
			<td>H</td>
		</tr>
		<tr>
			<td>{1,2,4,5,6,7,11,12,13,15,16,17}</td>
			<td>G</td>
			<td>F</td>
			<td>G</td>
		</tr>
		<tr>
			<td>{1,2,4,5,6,7,9,11,12,14,15,16,17}</td>
			<td>H</td>
			<td>F</td>
			<td>I</td>
		</tr>
		<tr>
			<td>{1,2,4,5,6,7,10,11,12,14,15,16,17}</td>
			<td>I</td>
			<td>F</td>
			<td>G</td>
		</tr>
	</tbody>
</table>
<p><strong>DFA</strong></p>
<p><img src="ch03/3.7/./assets/3.7.3-4-dfa.gif" alt="3 7 3-4-dfa" /></p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="exercises-for-section-38"><a class="header" href="#exercises-for-section-38">Exercises for Section 3.8</a></h1>
<h3 id="381"><a class="header" href="#381">3.8.1</a></h3>
<p>Suppose we have two tokens: (1) the keyword if, and (2)
id­entifiers, which are strings of letters other than if. Show:</p>
<ol>
<li>The NFA for these tokens, and</li>
<li>The DFA for these tokens.</li>
</ol>
<h4 id="answer-41"><a class="header" href="#answer-41">Answer</a></h4>
<ol>
<li>
<p>NFA</p>
<p><img src="ch03/3.8/./assets/3.8.1-nfa.gif" alt="3 8 1-nfa" /></p>
<p>NOTE: this NFA has potential conflict, we can decide the matched lexeme by 1. take the longest 2. take the first listed.</p>
</li>
<li>
<p>DFA</p>
<p><img src="ch03/3.8/./assets/3.8.1-dfa.gif" alt="3 8 1-dfa" /></p>
</li>
</ol>
<h3 id="382"><a class="header" href="#382">3.8.2</a></h3>
<p>Repeat Exercise 3.8.1 for tokens consisting of (1) the keyword
while, (2) the keyword when, and (3) identifiers consisting of strings of letters
and digits, beginning with a letter.</p>
<h4 id="answer-42"><a class="header" href="#answer-42">Answer</a></h4>
<ol>
<li>
<p>NFA</p>
<p><img src="ch03/3.8/./assets/3.8.2-nfa.gif" alt="3 8 2-nfa" /></p>
</li>
<li>
<p>DFA</p>
<p>bother to paint</p>
</li>
</ol>
<h3 id="383-"><a class="header" href="#383-">3.8.3 !</a></h3>
<p>Suppose we were to revise the definition of a DFA to allow
zero or one transition out of each state on each input symbol (rather than
exactly one such transition, as in the standard DFA definition). Some regular
expressions would then have smaller &quot;DFA's&quot; than they do under the standard
definition of a DFA. Give an example of one such regular expression.</p>
<h4 id="answer-43"><a class="header" href="#answer-43">Answer</a></h4>
<p>Take the language defined by regular expression &quot;ab&quot; as the example, assume that the set of input symbols is {a, b} </p>
<p>Standard DFA</p>
<p><img src="ch03/3.8/./assets/3.8.3-1.gif" alt="3 8 3-1" /></p>
<p>Revised DFA</p>
<p><img src="ch03/3.8/./assets/3.8.3-2.gif" alt="3 8 3-2" /></p>
<p>Obviously, the revised DFA is smaller than the standard DFA.</p>
<h3 id="384-"><a class="header" href="#384-">3.8.4 !!</a></h3>
<p>Design an algorithm to recognize Lex-lookahead patterns of
the form rl/r2, where rl and r2 are regular expressions. Show how your
algo­rithm works on the following inputs:</p>
<ol>
<li>(abcd|abc)/d</li>
<li>(a|ab)/ba</li>
<li>aa*/a*</li>
</ol>
<div style="break-before: page; page-break-before: always;"></div><h1 id="exercises-for-section-39"><a class="header" href="#exercises-for-section-39">Exercises for Section 3.9</a></h1>
<h3 id="391"><a class="header" href="#391">3.9.1</a></h3>
<p>Extend the table of Fig. 3.58 to include the operators</p>
<ol>
<li>？</li>
<li>
<ul>
<li></li>
</ul>
</li>
</ol>
<h4 id="answer-44"><a class="header" href="#answer-44">Answer</a></h4>
<table>
    <thead>
        <tr>
            <th>node n</th>
            <th>nullable(n)</th>
            <th>firstpos(n)</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>n = c_1 ?</td>
            <td>true</td>
            <td>firstpos(c_1)</td>
        </tr>
        <tr>
            <td>n = c_1 +</td>
            <td>nullable(c_1)</td>
            <td>firstpos(c_1)</td>
        </tr>
    </tbody>
</table>
<h3 id="392"><a class="header" href="#392">3.9.2</a></h3>
<p>Use Algorithm 3.36 to convert the regular expressions of
Ex­ercise 3.7.3 directly to deterministic finite automata.</p>
<h4 id="answer-45"><a class="header" href="#answer-45">Answer</a></h4>
<ol>
<li>(a|b)*</li>
</ol>
<ul>
<li>Syntax tree</li>
</ul>
<p><img src="ch03/3.9/./assets/3.9.2-1-1.gif" alt="3 9 2-1-1" /></p>
<ul>
<li>firstpos and lastpos for nodes in the syntax tree</li>
</ul>
<p><img src="ch03/3.9/./assets/3.9.2-1-2.gif" alt="3 9 2-1-2" /></p>
<ul>
<li>The function followpos</li>
</ul>
<table>
<thead>
<tr>
<th>node n</th>
<th>followpos(n)</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td>
<td>{1, 2, 3}</td>
</tr>
<tr>
<td>2</td>
<td>{1, 2, 3}</td>
</tr>
<tr>
<td>3</td>
<td>∅</td>
</tr>
</tbody>
</table>
<ul>
<li>Steps</li>
</ul>
<p>The value of firstpos for the root of the tree is {1, 2, 3}, so this set is the start state of D. Call this set of states A. We compute Dtran[A, a] and Dtran[A, b]. Among the positions of A, 1 correspond to a, while 2 correspond to b. Thus Dtran[A, a] = followpos(1) = {1, 2, 3}， Dtran[A, b] = followpos(2) = {1, 2, 3}. Both the results are set A, so dose not have new state, end the computation.</p>
<ul>
<li>DFA</li>
</ul>
<p><img src="https://f.cloud.github.com/assets/340282/457270/916fb2b6-b38f-11e2-9ad2-d3445e758b5e.gif" alt="3 9 2-1-dfa" /></p>
<ol start="2">
<li>
<p>(a*|b*)*</p>
</li>
<li>
<p>((ε|a)|b*)*</p>
</li>
<li>
<p>(a|b)*abb(a|b)*</p>
</li>
</ol>
<h3 id="393-"><a class="header" href="#393-">3.9.3 !</a></h3>
<p>We can prove that two regular expressions are equivalent by showing that their minimum-state DFA's are the same up to renaming of states. Show in this way that the following regular expressions: (a|b)*, (a*|b*)*, and ((ε|a)b*)* are all equivalent. <strong>Note</strong>: You may have constructed the DFA's for these expressions in response to Exercise 3.7.3.</p>
<h4 id="answer-46"><a class="header" href="#answer-46">Answer</a></h4>
<p>Refer to the answers of 3.7.3 and 3.9.2-1</p>
<h3 id="394-"><a class="header" href="#394-">3.9.4 !</a></h3>
<p>Construct the minimum-state DFA's for the following regular expressions:</p>
<ol>
<li>(a|b)*a(a|b)</li>
<li>(a|b)*a(a|b)(a|b)</li>
<li>(a|b)*a(a|b)(a|b)(a|b)</li>
</ol>
<p>Do you see a pattern?</p>
<h3 id="395-"><a class="header" href="#395-">3.9.5 !!</a></h3>
<p>To make formal the informal claim of Example 3.25, show that any deterministic finite automaton for the regular expression</p>
<p>(a|b)*a(a|b)...(a|b) where (a|b) appears n - 1 times at the end, must have at least 2n states. </p>
<p><strong>Hint</strong>: Observe the pattern in Exercise 3.9.4. What condition regarding the history of inputs does each state represent?</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="chapter-4"><a class="header" href="#chapter-4">Chapter 4</a></h1>
<p>Chapter 4: Syntax Analysis</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="第4章要点"><a class="header" href="#第4章要点">第4章要点</a></h1>
<h3 id="lr0-slr-lr-lalr-之间的区别"><a class="header" href="#lr0-slr-lr-lalr-之间的区别">！LR(0), SLR, LR, LALR 之间的区别</a></h3>
<h4 id="lr0分析法"><a class="header" href="#lr0分析法">LR(0)分析法</a></h4>
<p>p157: LR(0) 自动机是如何做出移入-规约决定的？假设文法符号串 γ 使得 LR(0) 自动机从开始状态 0 运行到某个状态 j，那么如果下一个输入符号为 a 且状态 j 有一个在 a 上的转换（即存在GOTO(j, a)），就移入 a；否则就进行规约。</p>
<p>这种方法会导致一些错误的规约，假定规约后的符号为 X，但 a 并不在 FOLLOW(X) 中，这种情况下就会有问题。所以 SLR 在这方面进行了改进。</p>
<h4 id="slr分析法"><a class="header" href="#slr分析法">SLR分析法</a></h4>
<p>SLR = Simple LR(1)</p>
<p>p161：构造一个 SLR 分析表时，如果 [A -&gt; α.] 在 I_i 中，那么对于 FOLLOW(A) 中的所有 a，将 ACTION[i, a] 设置为 “规约 A -&gt; α”</p>
<p>SLR 一定程度上解决了错误规约的问题，但没有完全解决。因为虽然 a 在 FOLLOW(A) 中才会选择规约，但是就当前所处的状态 I_i 而言，并不是每个 FOLLOW(A) 中的终结符都可以出现在状态 I_i 中的 A 后面。</p>
<p>p166: 用更正式一点的语言来讲，必须要为 I_i 精确得指明**哪些输入符号（即Follow Set）**可以更在句柄 α 后面，从而使 α 可以被规约为 A。</p>
<h4 id="lr1分析法lalr分析法"><a class="header" href="#lr1分析法lalr分析法">LR(1)分析法&amp;LALR分析法</a></h4>
<p>LR（或称为：规范LR、LR(1)） 通过在项中加入第二个分量，即向前看符号来解决这个问题。但新的问题是 LR 会使得状态表及其庞大，而 LALR 就是一种比较经济的做法，它具有和 SLR <strong>一样多的状态</strong>。</p>
<p>p170：一般地说，通过将LR(1)中具有相同核心项集的 LR 项集合并，可以得到 LALR 项集。虽然 LALR 可能会进行一些错误的规约，但最终会在输入任何新的符号之前发现这个错误。</p>
<h4 id="ll分析法与lr分析法的比较"><a class="header" href="#ll分析法与lr分析法的比较">LL分析法与LR分析法的比较</a></h4>
<p>LL分析法：自顶向下的分析方法</p>
<p>LL分析法的关键在于匹配与推导。匹配是借助TokenSequence.Peek完成的。</p>
<p>LL分析法的第二个<code>L</code>告诉我们，被分析的文法必须经过 <strong>提取左公因子</strong> 或 <strong>消除左递归</strong> 来满足特殊要求。而LR系列分析法则不需要。</p>
<p>LR系列分析法：自底向上的分析方法</p>
<p>移入（shift）与归约（reduce），分别是匹配（match）与推导（produce）的逆过程。</p>
<p>归约是推导的逆函数，那么如何生成这个逆函数，关键在于选取正确的产生式，我们称这个产生式为句柄（handle）。</p>
<p>LR分析项：用一个小点来分隔“已经识别的输入”与“对特定输入的期望”，且这种期望是可以转移的。</p>
<h4 id="lr各分析法的分析能力的比较"><a class="header" href="#lr各分析法的分析能力的比较">LR各分析法的分析能力的比较</a></h4>
<p>语法分析能力：LR(0) &lt; SLR(1) &lt; LALR(1) &lt; LR(1)；LL(1) &lt;&lt;&lt; LR(1)</p>
<blockquote>
<p>分析能力的体现：
方法越精细肯定冲突越少；越精细体现为中间状态数越多；
分析能力 正比于 精细程度 正比于 中间状态数 反比于 冲突数。</p>
</blockquote>
<h3 id="消除二义性-p134"><a class="header" href="#消除二义性-p134">消除二义性 （p134）</a></h3>
<p>图 4-10，如何得出这个消除方法的？</p>
<h3 id="消除左递归-p135"><a class="header" href="#消除左递归-p135">消除左递归 （p135）</a></h3>
<p>为什么图 4-11 的算法能消除文法中的左递归？</p>
<p>消除递归需满足两个条件：</p>
<ol>
<li>不存在立即左递归，即不存在形似这样的产生式 A -&gt; Aα 。</li>
<li>不存在由多步推导可产生的左递归。</li>
</ol>
<p>算法 3~5 行循环的结果使得形如 A_i -&gt; A_m α 的产生式一定满足 m &gt;= i ，就消除了形如 S =&gt; Aa =&gt; Sda 这样的转换可能，也就是说由 A_m 一定推导不出以 A_i 开头的产生式，A_m α 就不存在产生 A-i 左递归的可能。</p>
<p><strong>同时需要注意的是：</strong> 只需要处理 A_i -&gt; A_j α 这样的产生式，而不需要处理形如 A_i -&gt; α A_j β 这样的产生式</p>
<p>循环完成后，第 6 行消除了替换后的产生式中的立即左递归。</p>
<h3 id="使用-lr0-创建出-lalr1-项集的内核-p173"><a class="header" href="#使用-lr0-创建出-lalr1-项集的内核-p173">使用 LR(0) 创建出 LALR(1) 项集的内核 （p173）</a></h3>
<p>自发生成的和传播的向前看符号</p>
<h3 id="cnf-和-bnf"><a class="header" href="#cnf-和-bnf">CNF 和 BNF</a></h3>
<ul>
<li><a href="http://en.wikipedia.org/wiki/Chomsky_normal_form">Chomsky normal form</a></li>
<li><a href="https://en.wikipedia.org/wiki/Backus%E2%80%93Naur_Form">Backus Naur Form</a></li>
</ul>
<h3 id="一个ll1-parser实例"><a class="header" href="#一个ll1-parser实例">一个LL(1) Parser实例</a></h3>
<p><a href="https://github.com/StLeoX/leoml">StLeoX/leoml: StLeoX's OCaml-syntax-like Language Compiler.</a></p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="exercises-for-section-42"><a class="header" href="#exercises-for-section-42">Exercises for Section 4.2</a></h1>
<h3 id="421"><a class="header" href="#421">4.2.1</a></h3>
<p>Consider the context-free grammar:</p>
<pre><code>S -&gt; S S + | S S * | a
</code></pre>
<p>and the string aa + a*.</p>
<ol>
<li>Give a leftmost derivation for the string.</li>
<li>Give a rightmost derivation for the string.</li>
<li>Give a parse tree for the string.</li>
<li>! Is the grammar ambiguous or unambiguous? Justify your answer.</li>
<li>! Describe the language generated by this grammar.</li>
</ol>
<h4 id="answer-47"><a class="header" href="#answer-47">Answer</a></h4>
<ol>
<li>S =lm=&gt; SS* =&gt; SS+S* =&gt; aS+S* =&gt; aa+S* =&gt; aa+a*</li>
<li>S =rm=&gt; SS* =&gt; Sa* =&gt; SS+a* =&gt; Sa+a* =&gt; aa+a*</li>
<li></li>
</ol>
<pre><code>![4 2 1](./assets/4.2.1.gif)
</code></pre>
<ol start="4">
<li>Unambiguous</li>
<li>The set of all postfix expressions consist of addition and multiplication</li>
</ol>
<h3 id="422"><a class="header" href="#422">4.2.2</a></h3>
<p>Repeat Exercise 4 . 2 . 1 for each of the following grammars and strings:</p>
<ol>
<li>
<p>S -&gt; 0 S 1 | 0 1 with string 00011l.</p>
</li>
<li>
<p>S -&gt; + S S | * S S | a with string + * aaa.</p>
</li>
<li>
<p>! S -&gt; S (S) S | ε with string (()())</p>
</li>
<li>
<p>! S -&gt; S + S | S S | (S) | S * | a with string (a+a)*a</p>
</li>
<li>
<p>! S -&gt; (L) | a 以及 L -&gt; L, S | S with string ((a,a),a,(a))</p>
</li>
<li>
<p>!! S -&gt; a S b S | b S a S | ε with string aabbab</p>
</li>
<li>
<p>The following grammar for boolean expressions:</p>
<pre><code>bexpr -&gt; bexpr or bterm | bterm
bterm -&gt; bterm and bfactor | bfactor
bfactor -&gt; not bfactor | (bexpr) | true | false
</code></pre>
</li>
</ol>
<h4 id="answer-48"><a class="header" href="#answer-48">Answer</a></h4>
<ol>
<li>S =lm=&gt; 0S1 =&gt; 00S11 =&gt; 000111</li>
<li>S =rm=&gt; 0S1 =&gt; 00S11 =&gt; 000111</li>
<li>Omit</li>
<li>Unambiguous</li>
<li>The set of all strings of 0s and followed by an equal number of 1s</li>
</ol>
<p>2、</p>
<ol>
<li>S =lm=&gt; +SS =&gt; +*SSS =&gt; +*aSS =&gt; +*aaS =&gt; +*aaa</li>
<li>S =rm=&gt; +SS =&gt; +Sa =&gt; +*SSa =&gt; +*Saa =&gt; +*aaa</li>
<li>Omit</li>
<li>Unambiguous</li>
<li>The set of all prefix expressions consist of addition and multiplication.</li>
</ol>
<p>3、</p>
<ol>
<li>S =lm=&gt; S(S)S =&gt; (S)S =&gt; (S(S)S)S =&gt; ((S)S)S =&gt; (()S)S =&gt; (()S(S)S)S =&gt; (()(S)S)S =&gt; (()()S)S =&gt; (()())S =&gt; (()())</li>
<li>S =rm=&gt; S(S)S =&gt; S(S) =&gt; S(S(S)S) =&gt; S(S(S)) =&gt; S(S()) =&gt; S(S(S)S()) =&gt; S(S(S)()) =&gt; S(S()()) =&gt; S(()()) =&gt; (()())</li>
<li>Omit</li>
<li>Ambiguous</li>
<li>The set of all strings of symmetrical parentheses</li>
</ol>
<p>4、</p>
<ol>
<li>S =lm=&gt; SS =&gt; S*S =&gt; (S)*S =&gt; (S+S)*S =&gt; (a+S)*S =&gt; (a+a)*S =&gt; (a+a)*a</li>
<li>S =rm=&gt; SS =&gt; Sa =&gt; S*a =&gt; (S)*a =&gt; (S+S)*a =&gt; (S+a)*a =&gt; (a+a)*a</li>
<li>Omit</li>
<li>Ambiguous</li>
<li>The set of all string of plus, mupplication, 'a' and symmetrical parentheses, and plus is not the beginning and end of the position, multiplication is not the beginning of the position</li>
</ol>
<p>5、</p>
<ol>
<li>S =lm=&gt; (L) =&gt; (L, S) =&gt; (L, S, S) =&gt; ((S), S, S) =&gt; ((L), S, S) =&gt; ((L, S), S, S) =&gt; ((S, S), S, S) =&gt; ((a, S), S, S) =&gt; ((a, a), S, S) =&gt; ((a, a), a, S) =&gt; ((a, a), a, (L)) =&gt; ((a, a), a, (S)) =&gt; ((a, a), a, (a))</li>
<li>S =rm=&gt; (L) =&gt; (L, S) =&gt; (L, (L)) =&gt; (L, (a)) =&gt; (L, S, (a)) =&gt; (L, a, (a)) =&gt; (S, a, (a)) =&gt; ((L), a, (a)) =&gt; ((L, S), a, (a)) =&gt; ((S, S), a, (a)) =&gt; ((S, a), a, (a)) =&gt; ((a, a), a, (a))</li>
<li>Omit</li>
<li>Unambiguous</li>
<li>Something like tuple in Python</li>
</ol>
<p>6、</p>
<ol>
<li>S =lm=&gt; aSbS =&gt; aaSbSbS =&gt; aabSbS =&gt; aabbS =&gt; aabbaSbS =&gt; aabbabS =&gt; aabbab</li>
<li>S =rm=&gt; aSbS =&gt; aSbaSbS =&gt; aSbaSb =&gt; aSbab =&gt; aaSbSbab =&gt; aaSbbab =&gt; aabbab</li>
<li>Omit</li>
<li>Ambiguous</li>
<li>The set of all strings of 'a's and 'b's of the equal number of 'a's and 'b's</li>
</ol>
<p>7、 Unambiguous, boolean expression</p>
<h3 id="423"><a class="header" href="#423">4.2.3</a></h3>
<p>Design grammars for the following languages:</p>
<ol>
<li>The set of all strings of 0s and 1s such that every 0 is immediately followed
by at least one 1.</li>
<li>! The set of all strings of 0s and 1s that are palindromes; that is, the string
reads the same backward as forward.</li>
<li>! The set of all strings of 0s and 1s with an equal number of 0s and 1s.</li>
<li>!! The set of all strings of 0s and 1s with an unequal number of 0s and 1s.</li>
<li>! The set of all strings of 0s and as in which 011 does not appear as a
substring.</li>
<li>!! The set of all strings of 0s and 1s of the form xy, where x&lt;&gt;y and x and y are of the same length.</li>
</ol>
<h4 id="answer-49"><a class="header" href="#answer-49">Answer</a></h4>
<p>1、</p>
<pre><code>S -&gt; (0?1)*
</code></pre>
<p>2、</p>
<pre><code>S -&gt; 0S0 | 1S1 | 0 | 1 | ε
</code></pre>
<p>3、</p>
<pre><code>S -&gt; 0S1S | 1S0S | ε
</code></pre>
<p>5、</p>
<pre><code>S -&gt; 1*(0+1?)*
</code></pre>
<h3 id="424"><a class="header" href="#424">4.2.4</a></h3>
<p>There is an extended grammar notation in common use.
In this notation, square and curly braces in production bodies are metasymbols
(like -&gt; or |) with the following meanings:</p>
<ol>
<li>Square braces around a grammar symbol or symbols denotes that these
constructs are optional. Thus, production A -&gt; X[Y]Z has the same
effect as the two productions A -&gt; XYZ and A -&gt; XZ.</li>
<li>Curly braces around a grammar symbol or symbols says that these sym­bols
may be repeated any number of times, including zero times. Thus,
A -&gt; X{YZ} has the same effect as the infinite sequence of productions
A -&gt; X, A -&gt; XYZ, A -&gt; XYZYZ, and so on.</li>
</ol>
<p>Show that these two extensions do not add power to grammars; that is, any
language that can be generated by a grammar with these extensions can be
generated by a grammar without the extensions.</p>
<h4 id="proof"><a class="header" href="#proof">Proof</a></h4>
<table>
    <thead>
        <tr>
            <th>extended grammar</th>
            <th>not extended grammar</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>A -> X[Y]Z</td>
            <td>A -> XZ | XYZ</td>
        </tr>
        <tr>
            <td>A -> X{YZ}</td>
            <td>A -> XB<br/>B -> YZB | ε</td>
        </tr>
    </tbody>
</table>
<h3 id="425"><a class="header" href="#425">4.2.5</a></h3>
<p>Use the braces described in Exercise 4.2.4 to simplify the
following grammar for statement blocks and conditional statements:</p>
<pre><code>stmt -&gt; if expr then stmt else stmt
      | if stmt them stmt
      | begin stmtList end
stmtList -&gt; stmt; stmtList | stmt
</code></pre>
<h4 id="answer-50"><a class="header" href="#answer-50">Answer</a></h4>
<pre><code>stmt -&gt; if expr then stmt [else stmt]
      | begin stmtList end
stmtList -&gt; stmt [; stmtList]
</code></pre>
<h3 id="426"><a class="header" href="#426">4.2.6</a></h3>
<p>Extend the idea of Exercise 4.2.4 to allow any regular expres­sion
of grammar symbols in the body of a production. Show that this extension
does not allow grammars to define any new languages.</p>
<h4 id="proof-1"><a class="header" href="#proof-1">Proof</a></h4>
<p>Every regular grammar has a corresponding not extended grammar</p>
<h3 id="427-"><a class="header" href="#427-">4.2.7 !</a></h3>
<p>A grammar symbol X (terminal or nonterminal) is useless if
there is no derivation of the form S =*=&gt; wXy =*=&gt; wxy. That is, X can never
appear in the derivation of any sentence.</p>
<ol>
<li>
<p>Give an algorithm to eliminate from a grammar all productions containing useless symbols.</p>
</li>
<li>
<p>Apply your algorithm to the grammar:</p>
<pre><code>S -&gt; 0 | A
A -&gt; AB
B -&gt; 1
</code></pre>
</li>
</ol>
<h3 id="428"><a class="header" href="#428">4.2.8</a></h3>
<p>The grammar in Fig. 4.7 generates declarations for a sin­gle
numerical identifier; these declarations involve four different, independent
properties of numbers.</p>
<pre><code>stmt -&gt; declare id optionList
optionList -&gt; optionList option | ε
option -&gt; mode | scale | precision | base
mode -&gt; real | complex
scale -&gt; fixed | floating
precision -&gt; single | double
base -&gt; binary | decimal
</code></pre>
<ol>
<li>
<p>Generalize the grammar of Fig. 4.7 by allowing n options Ai, for some
fixed n and for i = 1,2... ,n, where Ai can be either ai or bi· Your
grammar should use only 0(n) grammar symbols and have a total length
of productions that is O(n).</p>
</li>
<li>
<p>! The grammar of Fig. 4.7 and its generalization in part (a) allow declarations
that are contradictory and/or redundant, such as</p>
<p>declare foo real fixed real floating</p>
<p>We could insist that the syntax of the language forbid such declarations;
that is, every declaration generated by the grammar has exactly one value
for each of the n options. If we do, then for any fixed n there is only a finite
number of legal declarations. The language of legal declarations thus has
a grammar (and also a regular expression), as any finite language does.
The obvious grammar, in which the start symbol has a production for
every legal declaration has n! productions and a total production length
of O(n x n!). You must do better: a total production length that is O(n2^n)</p>
</li>
<li>
<p>!! Show that any grammar for part (b) must have a total production length of at least 2n.</p>
</li>
<li>
<p>What does part (c) say about the feasibility of enforcing nonredundancy
and noncontradiction among options in declarations via the syntax of the programming language?</p>
</li>
</ol>
<h4 id="answer-51"><a class="header" href="#answer-51">Answer</a></h4>
<p>1、</p>
<pre><code>stmt -&gt; declare id optionList
optionList -&gt; optionList option | ε
option -&gt; A_1 | A_2 | … | A_n
A_1 -&gt; a_1 | b_1
A_2 -&gt; a_2 | b_2
…
A_n -&gt; a_n | b_n
</code></pre>
<div style="break-before: page; page-break-before: always;"></div><h1 id="43-节的练习"><a class="header" href="#43-节的练习">4.3 节的练习</a></h1>
<h3 id="431"><a class="header" href="#431">4.3.1</a></h3>
<p>下面是一个只包含符号 a 和 b 的正则表达式文法。它使用 + 替代表示并运算的字符 | ，以避免和文法中作为元符号使用的竖线相混淆：</p>
<pre><code>rexpr -&gt; rexpr + rterm | rterm
rterm -&gt; rterm rfactor | rfactor
rfactor -&gt; rfactor * | rprimary
rprimary -&gt; a | b
</code></pre>
<ol>
<li>对这个文法提取左公因子。</li>
<li>提取左公因子的变换能使这个文法适用于自顶向下的语法分析技术吗？</li>
<li>提取左公因子之后，从原文法中消除左递归。</li>
<li>得到的文法适用于自顶向下的语法分析吗？</li>
</ol>
<h4 id="解答-6"><a class="header" href="#解答-6">解答</a></h4>
<ol>
<li>
<p>无左公因子</p>
</li>
<li>
<p>不适合。因为存在左递归，不适用LL(1)文法。</p>
</li>
<li>
<p>消除左递归后的新文法如下：<br />
rexpr -&gt; rterm A
A -&gt; + rterm A | ε
rterm -&gt; rfactor B
B -&gt; rfactor B | ε
rfactor -&gt; rprimary C
C -&gt; * C | ε
rprimary -&gt; a | b</p>
</li>
<li>
<p>适合？</p>
</li>
</ol>
<h3 id="432"><a class="header" href="#432">4.3.2</a></h3>
<p>对下面的文法重复练习 4.3.1</p>
<ol>
<li>练习 4.2.1 的文法</li>
<li>练习 4.2.2-1 的文法</li>
<li>练习 4.2.2-3 的文法</li>
<li>练习 4.2.2-5 的文法</li>
<li>练习 4.2.2-7 的文法</li>
</ol>
<h4 id="解答-7"><a class="header" href="#解答-7">解答</a></h4>
<ol>
<li>
<p>S -&gt; S S + | S S * | a</p>
<ol>
<li>
<p>提取左公因子</p>
<pre><code> S -&gt; S S A | a
 A -&gt; + | *
</code></pre>
</li>
<li>
<p>不适合</p>
</li>
<li>
<p>消除左递归</p>
<pre><code> // initial status
 1）S -&gt; S S A | a
 2) A -&gt; + | *
 
 // i = 1
 1) S -&gt; a B
 2) B -&gt; S A B | ε
 3) A -&gt; + | *
 
 // i = 2, j = 1
 1) S -&gt; a B
 2) B -&gt; a B A B | ε
 3) A -&gt; + | *
 
 // i = 3, j = 1 ~ 2
 // nothing changed
</code></pre>
</li>
<li>
<p>适合</p>
</li>
</ol>
</li>
<li>
<p>S -&gt; 0 S 1 | 0 1</p>
<ol>
<li>
<p>提取左公因子</p>
<pre><code> S -&gt; 0 A
 A -&gt; S 1 | 1
</code></pre>
</li>
<li>
<p>不适合，有间接左递归</p>
</li>
<li>
<p>消除左递归</p>
<pre><code> // initial status
 1) S -&gt; 0 A
 2) A -&gt; S 1 | 1
 
 // i = 1
 // nothing changed
 
 // i = 2, j = 1
 1) S -&gt; 0 A
 2) A -&gt; 0 A 1 | 1
</code></pre>
</li>
<li>
<p>合适</p>
</li>
</ol>
</li>
<li>
<p>S -&gt; S (S) S | ε</p>
<ol>
<li>
<p>无左公因子</p>
</li>
<li>
<p>不合适</p>
</li>
<li>
<p>消除左递归</p>
<pre><code> // initial status
 1) S -&gt; S (S) S | ε
 
 // i = 1
 1) S -&gt; A
 2) A -&gt; (S) S A | ε
 
 // i = 2, j = 1
 // nothing changed
</code></pre>
</li>
<li>
<p>合适</p>
</li>
</ol>
</li>
<li>
<p>S -&gt; (L) | a 以及 L -&gt; L, S | S</p>
<ol>
<li>
<p>无左公因子</p>
</li>
<li>
<p>不合适</p>
</li>
<li>
<p>消除左递归</p>
<pre><code> // initial status
 1) S -&gt; (L) | a
 2) L -&gt; L, S | S
 
 // i = 1
 // nothing changed
 
 // i = 2, j = 1
 1) S -&gt; (L) | a
 2) L -&gt; (L) A | a A
 3) A -&gt; , S A | ε
 
 // i = 3, j = 1~2
 // nothing changed
</code></pre>
</li>
<li>
<p>合适</p>
</li>
</ol>
</li>
</ol>
<h3 id="433-"><a class="header" href="#433-">4.3.3 ！</a></h3>
<p>下面文法的目的是消除 4.3.2 节中讨论的 “悬空-else 二义性”：</p>
<pre><code>stmt -&gt; if expr then stmt
      | matchedStmt
matchedStmt -&gt; if expr then matchedStmt else stmt
             | other
</code></pre>
<p>说明这个文法仍然是二义性的。</p>
<h4 id="解答-8"><a class="header" href="#解答-8">解答</a></h4>
<p>看一段示范代码，我们通过缩进来表示代码解析的层次结构</p>
<pre><code>if expr 
then 
    if expr 
    then matchedStmt 
    else
        if expr
        then matchedStmt
else stmt
</code></pre>
<p>这段代码还可以被解析成</p>
<pre><code>if expr 
then 
    if expr 
    then matchedStmt 
    else
        if expr
        then matchedStmt
        else stmt
</code></pre>
<p>所以这仍然是一个二义性的文法。原因在于 <code>matchedStmt -&gt; if expr then matchedStmt else stmt</code> 中的最后一个 <code>stmt</code>，如果包含 <code>else</code> 语句的话，既可以认为是属于这个 <code>stmt</code> 的，也可以认为是属于包含这个 <code>matchedStmt</code> 的语句的。</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="44-节的练习"><a class="header" href="#44-节的练习">4.4 节的练习</a></h1>
<h3 id="441"><a class="header" href="#441">4.4.1</a></h3>
<p>为下面的每个文法设计一个预测分析器，并给出预测分析表。你可能先要对文法进行提取左公因子或者消除左递归的操作。</p>
<p>练习 4.2.2 中 1 - 7 中的文法。</p>
<h4 id="解答-9"><a class="header" href="#解答-9">解答</a></h4>
<ol>
<li>
<p>S -&gt; 0 S 1 | 0 1</p>
<p>step1. 提取左公因子</p>
<pre><code> S -&gt; 0 A
 A -&gt; S 1 | 1
</code></pre>
<p>step2. 消除左递归</p>
<pre><code> S -&gt; 0 A
 A -&gt; 0 A 1 | 1
</code></pre>
<p>step3. 预测分析表</p>
<table>
     <thead>
         <tr>
             <th rowspan="2">非终结符号</th>
             <th colspan="3">输入符号</th>
         </tr>
         <tr>
             <th>0</th>
             <th>1</th>
             <th>$</th>
         </tr>
     </thead>
     <tbody>
         <tr>
             <th>S</th>
             <td>S -> 0 A</td>
             <td></td>
             <td></td>
         </tr>
         <tr>
             <th>A</th>
             <td>A -> 0 A 1</td>
             <td>A -> 1</td>
             <td></td>
         </tr>
     </tbody>
 </table>
</li>
<li>
<p>S -&gt; + S S | * S S | a</p>
<p>step1. 无左公因子</p>
<p>step2. 无左递归</p>
<p>step3. 预测分析表</p>
<table>
     <thead>
         <tr>
             <th rowspan="2">非终结符号</th>
             <th colspan="4">输入符号</th>
         </tr>
         <tr>
             <th>+</th>
             <th>*</th>
             <th>a</th>
             <th>$</th>
         </tr>
     </thead>
     <tbody>
         <tr>
             <th>S</th>
             <td>S -> + S S</td>
             <td>S -> * S S</td>
             <td>S -> a</td>
             <td></td>
         </tr>
     </tbody>
 </table>
</li>
<li>
<p>! S -&gt; S (S) S | ε</p>
<p>step1. 无左公因子</p>
<p>step2. 消除左递归</p>
<pre><code> S -&gt; A
 A -&gt; (S) S A | ε
</code></pre>
<p>step3. 预测分析表</p>
<table>
     <thead>
         <tr>
             <th rowspan="2">非终结符号</th>
             <th colspan="3">输入符号</th>
         </tr>
         <tr>
             <th>(</th>
             <th>)</th>
             <th>$</th>
         </tr>
     </thead>
     <tbody>
         <tr>
             <th>S</th>
             <td>S -> A</td>
             <td>S -> A</td>
             <td>S -> A</td>
         </tr>
         <tr>
             <th>A</th>
             <td>A -> (S) S A<br/>A -> ε</td>
             <td>A -> ε</td>
             <td>A -> ε</td>
         </tr>
     </tbody>
 </table>
</li>
<li>
<p>! S -&gt; S + S | S S | (S) | S * | a</p>
<p>step1. 提取左公因子</p>
<pre><code> S -&gt; SA | (S) | a
 A -&gt; +S | S | *
</code></pre>
<p>进一步提取终结符</p>
<pre><code> S -&gt; SA | T
 A -&gt; +S | S | *
 T -&gt; (S) | a  
</code></pre>
<p>step2. 消除左递归(根据 p135 的算法 4.19)</p>
<pre><code> i = 1
         S -&gt; TB
         B -&gt; AB | ε
         
 i = 2
     j = 1
         A -&gt; +S | TB | *
         
 i = 3
     j = 1
         无需处理
     j = 2
         无需处理
</code></pre>
<p>得到最终的产生式</p>
<pre><code> S -&gt; TB
 B -&gt; AB | ε
 A -&gt; +S | TB | *
 T -&gt; (S) | a  
</code></pre>
<p>step3. first &amp;&amp; follow</p>
<pre><code> first(T) = [(, a]
 first(A) = [+, *] + first(T) =[+, *, (, a]
 first(B) = [ε] + first(A) = [ε, +, *, (, a]
 first(S) = first(T) = [(, a]
 
 follow(T) = [$, +, *, (, a]
 follow(A) = [$, +, *, (, ), a]
 follow(B) = [$]
 follow(S) = [$, +, *, (, ), a]
</code></pre>
<p>step4. 预测分析表</p>
<table>
     <thead>
         <tr>
             <th rowspan="2">非终结符号</th>
             <th colspan="6">输入符号</th>
         </tr>
         <tr>
             <th>(</th>
             <th>)</th>
             <th>+</th>
             <th>*</th>
             <th>a</th>
             <th>$</th>
         </tr>
     </thead>
     <tbody>
         <tr>
             <th>S</th>
             <td>S -> TB</td>
             <td></td>
             <td></td>
             <td></td>
             <td>S -> TB</td>
             <td></td>
         </tr>
         <tr>
             <th>B</th>
             <td>B -> AB</td>
             <td></td>
             <td>B -> AB</td>
             <td>B -> AB</td>
             <td>B -> AB</td>
             <td>B -> ε</td>
         </tr>
         <tr>
             <th>A</th>
             <td>A -> TB</td>
             <td></td>
             <td>A -> +S</td>
             <td>A -> \*</td>
             <td>A -> TB</td>
             <td></td>
         </tr>
         <tr>
             <th>T</th>
             <td>T -> (S)</td>
             <td></td>
             <td></td>
             <td></td>
             <td>T -> a </td>
             <td></td>
         </tr>
     </tbody>
 </table>
</li>
<li>
<p>S -&gt; (L) | a 以及 L -&gt; L, S | S</p>
<p>step1. 无左公因子</p>
<p>step2. 消除左递归</p>
<pre><code> S -&gt; (L) | a
 L -&gt; SA
 A -&gt; ,SA | ε
</code></pre>
<p>step3. first &amp;&amp; follow</p>
<pre><code>first(S) = [(, a]
first(L) = [(, a]
first(A) = [\,, ε]   # \, 表示文法中的非终结符

follow(S) = [\,, ), $]
follow(L) = [)]
follow(A) = [)]
</code></pre>
<p>step4. 预测分析表</p>
 <table>
     <thead>
         <tr>
             <th rowspan="2">非终结符号</th>
             <th colspan="5">输入符号</th>
         </tr>
         <tr>
             <th>(</th>
             <th>)</th>
             <th>,</th>
             <th>a</th>
             <th>$</th>
         </tr>
     </thead>
     <tbody>
         <tr>
             <th>S</th>
             <td>S -> (L)</td>
             <td></td>
             <td></td>
             <td>S -> a</td>
             <td></td>
         </tr>
 		<tr>
             <th>L</th>
             <td>L -> SA</td>
             <td></td>
             <td></td>
             <td>L -> SA</td>
             <td></td>
         </tr>
         <tr>
             <th>A</th>
             <td></td>
             <td></td>
             <td>A -> ,SA</td>
             <td></td>
             <td></td>
         </tr>
     </tbody>
 </table>
</li>
<li>
<p>grammar for boolean expressions:</p>
<pre><code>bexpr -&gt; bexpr or bterm | bterm
bterm -&gt; bterm and bfactor | bfactor
bfactor -&gt; not bfactor | ( bexpr ) | true | false
</code></pre>
<p>step1. 无左公因子</p>
<p>step2. 消除左递归</p>
<pre><code>bexpr -&gt; bterm bexpr'
bexpr' -&gt; or bterm bexpr' | ε
bterm -&gt; bfactor bterm'
bterm' -&gt; and bfactor bterm' | ε
bfactor -&gt; not bfactor | (bexpr) | true | false
</code></pre>
<p>step3. first &amp;&amp; follow</p>
<pre><code>first(bexpr) = first(bterm) = first(bfactor) = [not, (, true, false]
first(bexpr') = [or, ε]
first(bterm') = [and, ε]

follow(bexpr) = follow(bexpr') = [), $]
follow(bterm) = follow(bterm') = [or, $]
follow(bfactor) = [and, $]
  
</code></pre>
<p>step4. 预测分析表</p>
<table>
     <thead>
         <tr>
             <th rowspan="2">非终结符号</th>
             <th colspan="8">输入符号</th>
         </tr>
         <tr>
             <th>and</th>
             <th>or</th>
             <th>not</th>
             <th>(</th>
             <th>)</th>
             <th>true</th>
             <th>false</th>
             <th>$</th>
         </tr>
     </thead>
     <tbody>
         <tr>
             <th>bexpr</th>
             <td></td>
             <td></td>
             <td>bexpr -> bterm bexpr'</td>
             <td>bexpr -> bterm bexpr'</td>
             <td></td>
             <td>bexpr -> bterm bexpr'</td>
             <td>bexpr -> bterm bexpr'</td>
             <td></td>
         </tr>
         <tr>
             <th>bexpr'</th>
             <td></td>
             <td>bexpr' -> or bterm bexpr'</td>
             <td></td>
             <td></td>
             <td>bexpr' -> ε</td>
             <td></td>
             <td></td>
             <td>bexpr' -> ε</td>
         </tr>
         <tr>
             <th>bterm</th>
             <td></td>
             <td></td>
             <td>bterm -> bfactor bterm'</td>
             <td>bterm -> bfactor bterm'</td>
             <td></td>
             <td>bterm -> bfactor bterm'</td>
             <td>bterm -> bfactor bterm'</td>
             <td></td>
         </tr>
         <tr>
             <th>bterm'</th>
             <td></td>
             <td>bterm' -> and bfactor bterm'</td>
             <td></td>
             <td></td>
             <td>bterm' -> ε</td>
             <td></td>
             <td></td>
             <td>bterm' -> ε</td>
         </tr>
         <tr>
             <th>bfactor</th>
             <td></td>
             <td></td>
             <td>bfactor -> not bfactor</td>
             <td>bfactor -> (bexpr)
             <td></td>
             <td>bfactor -> true</td>
             <td>bfactor -> false</td>
             <td></td>
         </tr>
     </tbody>
 </table>
</li>
</ol>
<h3 id="442-"><a class="header" href="#442-">4.4.2 ！！</a></h3>
<p>有没有可能通过某种方法修改练习 4.2.1 中的文法，构造出一个与该练习中的语言（运算分量为 a 的后缀表达式）对应的预测分析器？</p>
<h4 id="解答-10"><a class="header" href="#解答-10">解答</a></h4>
<pre><code>S -&gt; SS+ | SS* | a
</code></pre>
<p>step1. 提取左公因子</p>
<pre><code>S -&gt; SSA | a
A -&gt; + | *
</code></pre>
<p>step2. 消除左递归</p>
<pre><code>i = 1 
        S -&gt; aB
        B -&gt; SAB | ε
        A -&gt; + | *
i = 2
    j = 1
        S -&gt; aB
        B -&gt; aBAB | ε
        A -&gt; + | *
</code></pre>
<p>step3. 预测分析表</p>
<table>
    <thead>
        <tr>
            <th rowspan="2">非终结符号</th>
            <th colspan="4">输入符号</th>
        </tr>
        <tr>
            <th>+</th>
            <th>*</th>
            <th>a</th>
            <th>$</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <th>S</th>
            <td></td>
            <td></td>
            <td>S -> aB</td>
            <td></td>
        </tr>
        <tr>
            <th>A</th>
            <td>A -> +</td>
            <td>A -> *</td>
            <td></td>
            <td></td>
        </tr>
        <tr>
            <th>B</th>
            <td>B -> ε</td>
            <td>B -> ε</td>
            <td>B -> SAB</td>
            <td>B -> ε</td>
        </tr>
    </tbody>
</table>    
​    
<h3 id="443"><a class="header" href="#443">4.4.3</a></h3>
<p>计算练习 4.2.1 的文法的 FIRST 和 FOLLOW 集合。</p>
<h4 id="解答-11"><a class="header" href="#解答-11">解答</a></h4>
<ul>
<li>first(S) = [a]</li>
<li>follow(S) = [a, +, *]</li>
</ul>
<h3 id="444"><a class="header" href="#444">4.4.4</a></h3>
<p>计算练习 4.2.2 中各个文法的 FIRST 和 FOLLOW 集合。</p>
<h4 id="解答-12"><a class="header" href="#解答-12">解答</a></h4>
<ol>
<li>
<p>S -&gt; 0 S 1 | 0 1</p>
<ul>
<li>first(S) = [0]</li>
<li>follow(S) = [1, $]</li>
</ul>
</li>
<li>
<p>S -&gt; + S S | * S S | a</p>
<ul>
<li>first(S) = [+, *, a]</li>
<li>follow(S) = [+, *, a, $]</li>
</ul>
</li>
<li>
<p>S -&gt; S (S) S | ε</p>
<ul>
<li>first(S) = [(, ε]</li>
<li>followS(S) = [), $]</li>
</ul>
</li>
<li>
<p>S -&gt; S + S | S S | (S) | S * | a</p>
<ul>
<li>first(S) = [(, a]</li>
<li>follow(S) = [+, (, ), a, *, $]</li>
</ul>
</li>
<li>
<p>S -&gt; (L) | a 以及 L -&gt; L, S | S</p>
<ul>
<li>first(S) = [(, a]</li>
<li>follow(S) = [&quot;,&quot;, $]</li>
<li>first(L) = first(S) = [(, a]</li>
<li>follow(L) = [), &quot;,&quot;, $]</li>
</ul>
</li>
<li>
<p>S -&gt; a S b S | b S a S | ε</p>
<ul>
<li>first(S) = [a, b, ε]</li>
<li>follow(S) = [a, b, $]</li>
</ul>
</li>
<li>
<p>下面的布尔表达式对应的文法：</p>
<pre><code> bexpr -&gt; bexpr or bterm | bterm
 bterm -&gt; bterm and bfactor | bfactor
 bfactor -&gt; not bfactor | (bexpr) | true | false
</code></pre>
</li>
</ol>
<h3 id="445"><a class="header" href="#445">4.4.5</a></h3>
<p>文法 S -&gt; aSa | aa 生成了所有由 a 组成的长度为偶数的串。我们可以为这个文法设计一个带回溯的递归下降分析器。如果我们选择先用产生式 S -&gt; aa 展开，那么我们只能识别串 aa。因此，任何合理的递归下降分析器将首先尝试 S -&gt; aSa。</p>
<ol>
<li>！ 说明这个递归下降分析器识别输入 aa，aaaa 和 aaaaaaaa，但识别不了 aaaaaa。</li>
<li>！！ 这个递归下降分析器识别什么样的语言？</li>
</ol>
<hr />
<h3 id="注意"><a class="header" href="#注意">注意</a></h3>
<p>以下题目请参考 Aho 本人的讲义：<a href="http://www.cs.columbia.edu/%7Eaho/cs3261/lectures/12-10-08.htm">Aho: Properties of Context-Free Languages</a>，<a href="ch04/4.4/cs.columbia.edu-aho-cs3261-properties-of-cfl-121008.html">本地副本</a></p>
<p>此外还有<a href="http://courses.engr.illinois.edu/cs373/Lectures/lec14.pdf">另一篇内容相似的文章</a>，<a href="ch04/4.4/courses.engr.illinois.edu-cs373-lec14.pdf">本地副本</a></p>
<p>关于 CNF 和 CYK 算法，有较多相关资料，自行搜索</p>
<h3 id="446-"><a class="header" href="#446-">4.4.6 !</a></h3>
<p>如果一个文法没有产生式体为 ε 的产生式，那么这个文法就是无 ε 产生式的。</p>
<ol>
<li>给出一个算法，他的功能是把任何文法转变成一个无 ε 产生式的生成相同语言的文法（唯一可能的例外是空串——没有哪个无 ε 产生式的文法能生成 ε）。提示：首先找出所有可能为空的非终结符号。非终结符号可能为空是指它（可能通过很长的推导）生成 ε。</li>
<li>将你的算法应用于文法 S -&gt; aSbS | bSaS | ε</li>
</ol>
<h3 id="447-"><a class="header" href="#447-">4.4.7 ！</a></h3>
<p>单产生式是指其产生式体为单个非终结符号的产生式，即形如 A -&gt; B 的产生式。</p>
<ol>
<li>给出一个算法，它可以把任何文法转变成一个生成相同语言（唯一可能的例外是空串）的、无 ε 产生式、无单产生式的文法。提示：首先消除 ε 产生式，然后找出所有满足下列条件的非终结符号对 A 和 B：存在 A =*=&gt; B。</li>
<li>将你的算法应用于 4.1.2 节的算法。</li>
<li>说明作为 （1） 的一个结果，我们可以把一个文法转换成一个没有环的等价文法。</li>
</ol>
<h3 id="448-"><a class="header" href="#448-">4.4.8 ！！</a></h3>
<p>如果一个文法的每个产生式要么形如 A -&gt; BC，要么形如 A -&gt; a，那么这个文法就成为 Chomsky 范式（Chomsky Normal Form， CNF）。说明如何将任意文法转变成一个生成相同语言（唯一可能的例外是空串——没有 CNF 文法可以生成 ε）的 CNF 文法。</p>
<h3 id="449-"><a class="header" href="#449-">4.4.9 ！</a></h3>
<p>对于每个具有上下文无关的语法，其长度为 n 的串可以在 O(n^3) 的时间内完成识别。完成这种识别工作的一个简单方法称为 Cocke-Younger-Kasami（CYK）算法。该算法基于动态规划技术。也就是说，给定一个串 a_1a_2…a_n，我们构造出一个 nxn 的表 T 使得 T_ij 是可以生成子串 a_ia_i+1…aj 的非终结符号的集合。如果基础文法是 CNF 的，那么只要我们按照正确的顺序来填表：先填 j-i 值最小的条目，则表中的每一个条目都可以在 O(n) 时间内填写完毕。给出一个能够正确填写这个表的条目的算法，并说明你的算法的时间复杂度为  O(n^3)。填完这个表之后，你如何判断 a_1a_2…a_n 是否在这个语言中？</p>
<h3 id="4410-"><a class="header" href="#4410-">4.4.10 ！</a></h3>
<p>说明我们如何能够在填好练习 4.4.9 中的表之后，在 O(n) 的时间内获得 a_1a_2…a_n 对应的一颗语法分析树？提示：修改练习 4.4.9 中的表 T，使得对于表的每个条目 T_ij 中的每个非终结符号 A，这个表同时记录了其他条目中的哪两个非终结符号组成的对偶使得我们将 A 放到 T_ij 中。</p>
<h3 id="4411-"><a class="header" href="#4411-">4.4.11 ！</a></h3>
<p>修改练习 4.4.9 中的算法，使得对于任意符号串，他可以找出至少需要执行多少次插入、删除和修改错误（每个错误是一个字符）的操作才能将这个串变成基础文法的语言的句子。</p>
<h3 id="4412-"><a class="header" href="#4412-">4.4.12 ！</a></h3>
<pre><code>stmt -&gt; if e then stmt stmtTail
      | while e do stmt
      | begin list end
      | s
stmtTail -&gt; else stmt
          | ε
list -&gt; stmt listTail
listTail -&gt; ; list
          | ε
</code></pre>
<p>上面的代码给出了对应于某些语句的文法。你可以将 e 和 s 当做分别代表条件表达式和“其他语句”的终结符号。如果我们按照下列方法来解决因为展开可选“else”（非终结符号 stmtTail）而引起的冲突：当我们从输入中看到一个 else 时就选择消耗掉这个 else。使用 4.4.5 节中描述的同步符号的思想：</p>
<ol>
<li>为这个文法构造一个带有错误纠正信息的预测分析表。</li>
<li>给出你的语法分析器在处理下列输入时的行为：
<ol>
<li>if e then s; if e then s end</li>
<li>while e do begin s; if e then e; end</li>
</ol>
</li>
</ol>
<div style="break-before: page; page-break-before: always;"></div><h1 id="45-节的练习"><a class="header" href="#45-节的练习">4.5 节的练习</a></h1>
<h3 id="451"><a class="header" href="#451">4.5.1</a></h3>
<p>对于练习 4.2.2（a）中的文法 S -&gt; 0 S 1 | 0 1，指出下面各个最右句型的句柄。</p>
<ol>
<li>000111</li>
<li>00S11</li>
</ol>
<h4 id="解答-13"><a class="header" href="#解答-13">解答</a></h4>
<ol>
<li>01</li>
<li>0S1</li>
</ol>
<h3 id="452"><a class="header" href="#452">4.5.2</a></h3>
<p>对于练习 4.2.1 的文法 S -&gt; S S + | S S * | a 和下面各个最右句型，重复练习 4.5.1 。</p>
<ol>
<li>SSS+a*+</li>
<li>SS+a*a+</li>
<li>aaa*a++</li>
</ol>
<h4 id="解答-14"><a class="header" href="#解答-14">解答</a></h4>
<ol>
<li>SS+</li>
<li>SS+</li>
<li>a</li>
</ol>
<h3 id="453"><a class="header" href="#453">4.5.3</a></h3>
<p>对于下面的输入符号串和文法，说明相应的自底向上语法分析过程。</p>
<ol>
<li>练习 4.5.1 的文法的串 000111 。</li>
<li>练习 4.5.2 的文法的串 aaa*a++ 。</li>
</ol>
<h4 id="解答-15"><a class="header" href="#解答-15">解答</a></h4>
<p>1、 000111</p>
<table>
    <thead>
        <tr>
            <th>栈</th>
            <th>输入</th>
            <th>句柄</th>
            <th>动作</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>$</td>
            <td>000111$</td>
            <td></td>
            <td>移入</td>
        </tr>
        <tr>
            <td>$0</td>
            <td>00111$</td>
            <td></td>
            <td>移入</td>
        </tr>
        <tr>
            <td>$00</td>
            <td>0111$</td>
            <td></td>
            <td>移入</td>
        </tr>
        <tr>
            <td>$000</td>
            <td>111$</td>
            <td></td>
            <td>移入</td>
        </tr>
        <tr>
            <td>$0001</td>
            <td>11$</td>
            <td>01</td>
            <td>规约：S -> 01</td>
        </tr>
        <tr>
            <td>$00S</td>
            <td>11$</td>
            <td></td>
            <td>移入</td>
        </tr>
        <tr>
            <td>$00S1</td>
            <td>1$</td>
            <td>0S1</td>
            <td>规约：S -> 0S1 </td>
        </tr>
        <tr>
            <td>$0S</td>
            <td>1$</td>
            <td></td>
            <td>移入</td>
        </tr>
        <tr>
            <td>$0S1</td>
            <td>$</td>
            <td>0S1</td>
            <td>规约：S -> 0S1 </td>
        </tr>
        <tr>
            <td>$S</td>
            <td>$</td>
            <td></td>
            <td>接受</td>
        </tr>
    </tbody>
</table>
<p>2、 aaa*a++</p>
<table>
    <thead>
        <tr>
            <th>栈</th>
            <th>输入</th>
            <th>句柄</th>
            <th>动作</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>$</td>
            <td>aaa*a++$</td>
            <td></td>
            <td>移入</td>
        </tr>
        <tr>
            <td>$a</td>
            <td>aa*a++$</td>
            <td>a</td>
            <td>规约: S -> a</td>
        </tr>
        <tr>
            <td>$S</td>
            <td>aa*a++$</td>
            <td></td>
            <td>移入</td>
        </tr>
        <tr>
            <td>$Sa</td>
            <td>a*a++$</td>
            <td>a</td>
            <td>规约: S -> a</td>
        </tr>
        <tr>
            <td>$SS</td>
            <td>a*a++$</td>
            <td></td>
            <td>移入</td>
        </tr>
        <tr>
            <td>$SSa</td>
            <td>*a++$</td>
            <td>a</td>
            <td>规约: S -> a</td>
        </tr>
        <tr>
            <td>$SSS</td>
            <td>*a++$</td>
            <td></td>
            <td>移入</td>
        </tr>
        <tr>
            <td>$SSS*</td>
            <td>a++$</td>
            <td>SS*</td>
            <td>规约: S -> SS*</td>
        </tr>
        <tr>
            <td>$SS</td>
            <td>a++$</td>
            <td></td>
            <td>移入</td>
        </tr>
        <tr>
            <td>$SSa</td>
            <td>++$</td>
            <td>a</td>
            <td>规约: S -> a</td>
        </tr>
        <tr>
            <td>$SSS</td>
            <td>++$</td>
            <td></td>
            <td>移入</td>
        </tr>
        <tr>
            <td>$SSS+</td>
            <td>+$</td>
            <td>SS+</td>
            <td>规约: S -> SS+</td>
        </tr>
        <tr>
            <td>$SS</td>
            <td>+$</td>
            <td></td>
            <td>移入</td>
        </tr>
        <tr>
            <td>$SS+</td>
            <td>$</td>
            <td>SS+</td>
            <td>规约: S -> SS+</td>
        </tr>
        <tr>
            <td>$S</td>
            <td>$</td>
            <td></td>
            <td>接受</td>
        </tr>
    </tbody>
</table><div style="break-before: page; page-break-before: always;"></div><h1 id="46-节的练习"><a class="header" href="#46-节的练习">4.6 节的练习</a></h1>
<h3 id="461"><a class="header" href="#461">4.6.1</a></h3>
<p>描述下列文法的所有可行前缀</p>
<ol>
<li>练习4.2.2-1的文法 S-&gt;0S1|01</li>
<li>！ 练习4.2.1的文法 S-&gt;SS+|SS*|a</li>
<li>！ 练习4.2.2-3的文法 S-&gt;S(S)S|ε</li>
</ol>
<h4 id="解答-16"><a class="header" href="#解答-16">解答</a></h4>
<p>以下提取左公因子和消除左递归后的文法均由练习 4.3.2 得到</p>
<ol>
<li>
<p>提取左公因子和消除左递归后的增广文法</p>
<pre><code> 0) S' -&gt; S
 1) S -&gt; 0 A
 2) A -&gt; 0 A 1
 3) A -&gt; 1
</code></pre>
<p>LR(0) 自动机如下：</p>
<p><img src="ch04/4.6/./assets/4.6.1-1.gif" alt="4 6 1-1" /></p>
<p>可行前缀为 <code>0+A?1?</code></p>
</li>
<li>
<p>提取左公因子和消除左递归后的增广文法</p>
<pre><code> 0) S' -&gt; S
 1) S -&gt; a B
 2) B -&gt; a B A B
 3) B -&gt; ε
 4) A -&gt; +
 5) A -&gt; *
</code></pre>
<p>LR(0) 自动机如下：</p>
<p><img src="ch04/4.6/./assets/4.6.1-2.gif" alt="4 6 1-2" /></p>
<p>可行前缀为 <code>aB?|aaa*(BAa+)*(B|B+|B*|BA|BAB)?</code>，注意到B+和B*中的+和*都是文法中的非终结符。</p>
</li>
<li>
<p>提取左公因子和消除左递归后的增广文法</p>
<pre><code> 0) S' -&gt; S
 1) S -&gt; A
 2) A -&gt; (S) S A
 3) A -&gt; ε
</code></pre>
<p>LR(0) 自动机如下：</p>
<p><img src="ch04/4.6/./assets/4.6.1-3.gif" alt="4 6 1-3" /></p>
<p>DFA的转移很复杂，不归纳正则形式的活前缀。</p>
</li>
</ol>
<h3 id="462"><a class="header" href="#462">4.6.2</a></h3>
<p>为练习4.2.1中的（增广）文法构造SLR项集。计算这些项集的GOTO函数。给出这个函数的语法分析表。这个文法是SLR文法吗？</p>
<h4 id="解答-17"><a class="header" href="#解答-17">解答</a></h4>
<p>分析4.6.1-2的文法。该文法的项集和 GOTO 函数见 4.6.1-2</p>
<p>FOLLOW 函数如下：</p>
<pre><code>FOLLOW(S) = [$]
FOLLOW(A) = [a, $]
FOLLOW(B) = [+, * ,$]
</code></pre>
<p>语法分析表如下：</p>
<table>
    <thead>
        <tr>
            <th rowspan="2">状态</th>
            <th colspan="4">ACTION</th>
            <th colspan="3">GOTO</th>
        </tr>
        <tr>
            <th>a</th>
            <th>+</th>
            <th>*</th>
            <th>$</th>
            <th>S</th>
            <th>A</th>
            <th>B</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>0</td>
            <td>s2</td>
            <td></td>
            <td></td>
            <td></td>
            <td>s1</td>
            <td></td>
            <td></td>
        </tr>
        <tr>
            <td>1</td>
            <td></td>
            <td></td>
            <td></td>
            <td>acc</td>
            <td></td>
            <td></td>
            <td></td>
        </tr>
        <tr>
            <td>2</td>
            <td>s4</td>
            <td>r3</td>
            <td>r3</td>
            <td>r3</td>
            <td></td>
            <td></td>
            <td>s3</td>
        </tr>
        <tr>
            <td>3</td>
            <td></td>
            <td></td>
            <td></td>
            <td>r1</td>
            <td></td>
            <td></td>
            <td></td>
        </tr>
        <tr>
            <td>4</td>
            <td>s4</td>
            <td>r3</td>
            <td>r3</td>
            <td>r3</td>
            <td></td>
            <td></td>
            <td>s5</td>
        </tr>
        <tr>
            <td>5</td>
            <td></td>
            <td>s7</td>
            <td>s8</td>
            <td></td>
            <td></td>
            <td>s6</td>
            <td></td>
        </tr>
        <tr>
            <td>6</td>
            <td>s4</td>
            <td>r3</td>
            <td>r3</td>
            <td>r3</td>
            <td></td>
            <td></td>
            <td>s9</td>
        </tr>
        <tr>
            <td>7</td>
            <td>r4</td>
            <td></td>
            <td></td>
            <td>r4</td>
            <td></td>
            <td></td>
            <td></td>
        </tr>
        <tr>
            <td>8</td>
            <td>r5</td>
            <td></td>
            <td></td>
            <td>r5</td>
            <td></td>
            <td></td>
            <td></td>
        </tr>
        <tr>
            <td>9</td>
            <td></td>
            <td>r2</td>
            <td>r2</td>
            <td>r2</td>
            <td></td>
            <td></td>
            <td></td>
        </tr>
    </tbody>
</table>
<p>无冲突，这显然是一个 SLR 文法</p>
<h3 id="463"><a class="header" href="#463">4.6.3</a></h3>
<p>利用练习4.6.2得到的语法分析表，给出处理输入aa*a+时的各个动作。</p>
<h4 id="解答-18"><a class="header" href="#解答-18">解答</a></h4>
<table>
    <thead>
        <tr>
            <th></th>
            <th>栈</th>
            <th>符号</th>
            <th>输入</th>
            <th>动作</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>1)</td>
            <td>0</td>
            <td></td>
            <td>aa*a+$</td>
            <td>移入</td>
        </tr>
        <tr>
            <td>2)</td>
            <td>02</td>
            <td>a</td>
            <td>a*a+$</td>
            <td>移入</td>
        </tr>
        <tr>
            <td>3)</td>
            <td>024</td>
            <td>aa</td>
            <td>*a+$</td>
            <td>根据 B -> ε 规约</td>
        </tr>
        <tr>
            <td>4)</td>
            <td>0245</td>
            <td>aaB</td>
            <td>*a+$</td>
            <td>移入</td>
        </tr>
        <tr>
            <td>5)</td>
            <td>02458</td>
            <td>aaB*</td>
            <td>a+$</td>
            <td>根据 A -> * 规约</td>
        </tr>
        <tr>
            <td>6)</td>
            <td>02456</td>
            <td>aaBA</td>
            <td>a+$</td>
            <td>移入</td>
        </tr>
        <tr>
            <td>7)</td>
            <td>024564</td>
            <td>aaBAa</td>
            <td>+$</td>
            <td>根据 B -> ε 规约</td>
        </tr>
        <tr>
            <td>8)</td>
            <td>0245645</td>
            <td>aaBAaB</td>
            <td>+$</td>
            <td>移入</td>
        </tr>
        <tr>
            <td>9)</td>
            <td>02456457</td>
            <td>aaBAaB+</td>
            <td>$</td>
            <td>根据 A -> + 规约</td>
        </tr>
        <tr>
            <td>9)</td>
            <td>02456456</td>
            <td>aaBAaBA</td>
            <td>$</td>
            <td>根据 B -> ε 规约</td>
        </tr>
        <tr>
            <td>10)</td>
            <td>024564569</td>
            <td>aaBAaBAB</td>
            <td>$</td>
            <td>根据 B -> aBAB 规约</td>
        </tr>
        <tr>
            <td>11)</td>
            <td>024569</td>
            <td>aaBAB</td>
            <td>$</td>
            <td>根据 B -> aBAB 规约</td>
        </tr>
        <tr>
            <td>12)</td>
            <td>023</td>
            <td>aB</td>
            <td>$</td>
            <td>根据 S -> aB 规约</td>
        </tr>
        <tr>
            <td>13)</td>
            <td>01</td>
            <td>S</td>
            <td>$</td>
            <td>接受</td>
        </tr>
    </tbody>
</table>
<h3 id="464"><a class="header" href="#464">4.6.4</a></h3>
<p>对于练习4.2.2-1~4.2.2-7中的各个（增广）文法：</p>
<ol>
<li>构造SLR项集和他们的GOTO函数</li>
<li>指出你的项集中的所有动作冲突</li>
<li>如果存在SLR语法分析表，构造出这个语法分析表</li>
</ol>
<h4 id="2"><a class="header" href="#2">2)</a></h4>
<p>增广文法G2': </p>
<pre><code>0) S' -&gt; S
1) S -&gt; +SS
2) S -&gt; *SS
3) S -&gt; a
</code></pre>
<p>LR(0) 自动机如下：</p>
<p><img src="ch04/4.6/./assets/4.6.4-2.png" alt="4 6 4-2" /></p>
<p>Follow函数如下：</p>
<pre><code>Follow(S) = [$, +, *, a]
</code></pre>
<p>SLR语法分析表如下：</p>
<table>
    <thead>
        <tr>
            <th rowspan="2">状态</th>
            <th colspan="4">ACTION</th>
            <th colspan="1">GOTO</th>
        </tr>
        <tr>
            <th>a</th>
            <th>+</th>
            <th>*</th>
            <th>$</th>
            <th>S</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>0</td>
            <td>s4</td>
            <td>s2</td>
            <td>s3</td>
            <td></td>
            <td>1</td>
        </tr>
        <tr>
            <td>1</td>
            <td></td>
            <td></td>
            <td></td>
            <td>acc</td>
            <td></td>
        </tr>
        <tr>
            <td>2</td>
            <td>s4</td>
            <td>s2</td>
            <td>s3</td>
            <td></td>
            <td>5</td>
        </tr>
        <tr>
            <td>3</td>
            <td>s4</td>
            <td>s2</td>
            <td>s3</td>
            <td></td>
            <td>6</td>
        </tr>
        <tr>
            <td>4</td>
            <td>r3</td>
            <td>r3</td>
            <td>r3</td>
            <td>r3</td>
            <td></td>
        </tr>
        <tr>
            <td>5</td>
            <td>s4</td>
            <td>s2</td>
            <td>s3</td>
            <td></td>
            <td>7</td>
        </tr>
        <tr>
            <td>6</td>
            <td>s4</td>
            <td>s2</td>
            <td>s3</td>
            <td></td>
            <td>8</td>
        </tr>
        <tr>
            <td>7</td>
            <td>r1</td>
            <td>r1</td>
            <td>r1</td>
            <td>r2</td>
            <td></td>
        </tr>
        <tr>
            <td>8</td>
            <td>r2</td>
            <td>r2</td>
            <td>r2</td>
            <td>r2</td>
            <td></td>
        </tr>
    </tbody>
</table>
<p>不存在s/r冲突，也不存在r/r冲突，故文法G2'属于SLR文法。</p>
<h4 id="5"><a class="header" href="#5">5)</a></h4>
<p>增广文法G5': </p>
<pre><code>0) S' -&gt; S
1) S -&gt; (L)
2) S -&gt; a
3) L -&gt; SA
4) A -&gt; ,SA
5) A -&gt; ε
</code></pre>
<p>LR(0)自动机如下：</p>
<p><img src="ch04/4.6/./assets/4.6.4-5.png" alt="4 6 4-5" /></p>
<p>Follow函数如下：</p>
<pre><code>Follow(S) = [$, \,, )]
Follow(L) = [)]
Follow(A) = [)]
</code></pre>
<table>
    <thead>
        <tr>
            <th rowspan="2">状态</th>
            <th colspan="5">ACTION</th>
            <th colspan="3">GOTO</th>
        </tr>
        <tr>
            <th>(</th>
            <th>a</th>
            <th>,</th>
            <th>)</th>
            <th>$</th>
            <th>S</th>
            <th>L</th>
            <th>A</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>0</td>
            <td>s2</td>
            <td>s2</td>
            <td></td>
            <td></td>
            <td></td>
            <td>1</td>
            <td></td>
            <td></td>
        </tr>
        <tr>
            <td>1</td>
            <td></td>
            <td></td>
            <td></td>
            <td></td>
            <td>acc</td>
            <td></td>
            <td></td>
            <td></td>
        </tr>
        <tr>
            <td>2</td>
            <td>s2</td>
            <td>s3</td>
            <td></td>
            <td></td>
            <td></td>
            <td>5</td>
            <td>4</td>
            <td></td>
        </tr>
        <tr>
            <td>3</td>
            <td></td>
            <td></td>
            <td>r2</td>
            <td>r2</td>
            <td>r2</td>
            <td></td>
            <td></td>
            <td></td>
        </tr>
        <tr>
            <td>4</td>
            <td></td>
            <td></td>
            <td></td>
            <td>s10</td>
            <td></td>
            <td></td>
            <td></td>
            <td></td>
        </tr>
        <tr>
            <td>5</td>
            <td></td>
            <td></td>
            <td>s7</td>
            <td>r5</td>
            <td></td>
            <td></td>
            <td></td>
            <td>6</td>
        </tr>
        <tr>
            <td>6</td>
            <td></td>
            <td></td>
            <td></td>
            <td>r3</td>
            <td></td>
            <td></td>
            <td></td>
            <td></td>
        </tr>
        <tr>
            <td>7</td>
            <td>s2</td>
            <td>s3</td>
            <td></td>
            <td></td>
            <td></td>
            <td>8</td>
            <td></td>
            <td></td>
        </tr>
        <tr>
            <td>8</td>
            <td></td>
            <td></td>
            <td>s7</td>
            <td>r5</td>
            <td></td>
            <td></td>
            <td></td>
            <td>9</td>
        </tr>
        <tr>
            <td>9</td>
            <td></td>
            <td></td>
            <td></td>
            <td>r4</td>
            <td></td>
            <td></td>
            <td></td>
            <td></td>
        </tr>
        <tr>
            <td>10</td>
            <td></td>
            <td></td>
            <td>r1</td>
            <td>r1</td>
            <td>r1</td>
            <td></td>
            <td></td>
            <td></td>
        </tr>
    </tbody>
</table>
<p>不存在s/r冲突，也不存在r/r冲突，故文法G5'属于SLR文法。</p>
<h3 id="465"><a class="header" href="#465">4.6.5</a></h3>
<p>说明下面的文法</p>
<pre><code>S-&gt;AaAb|BbBa
A-&gt;ε
B-&gt;ε
</code></pre>
<p>是LL(1)的，但不是SLR(1)的。</p>
<h4 id="解答-19"><a class="header" href="#解答-19">解答</a></h4>
<ol>
<li>
<p>该文法是 LL(1) 的</p>
<p>见 4.4.3 节，p142 的判定标准</p>
</li>
<li>
<p>该文法不是 SLR(1) 的</p>
<pre><code> I_0
 
 S' -&gt; .S
 S -&gt; .AaAb
 S -&gt; .BbBa
 A -&gt; .
 B -&gt; .
</code></pre>
<p>由于 FOLLOW(A) = FOLLOW(B) = [a, b]，所以当 I_0 后输入为 a 或 b 时，就会发生规约冲突。</p>
</li>
</ol>
<h3 id="466"><a class="header" href="#466">4.6.6</a></h3>
<p>说明下面的文法</p>
<pre><code>S-&gt;SA|A
A-&gt;a
</code></pre>
<p>是SLR(1)的，但不是LL(1)的</p>
<h4 id="解答-20"><a class="header" href="#解答-20">解答</a></h4>
<ol>
<li>
<p>该文法不是 LL(1) 的</p>
<p><code>S -&gt; SA</code> 和 <code>S -&gt; A</code> 均能推导出以 a 开头的串，所以不是 LL(1) 的</p>
</li>
<li>
<p>该文法是 SLR(1) 的</p>
<p>该文法生成的语法分析表是没有冲突的</p>
</li>
</ol>
<h3 id="467"><a class="header" href="#467">4.6.7!!</a></h3>
<p>考虑按照下面的方式定义的文法族 G_n：</p>
<pre><code>S -&gt; A_i b_i         其中1&lt;=i&lt;=n
A_i-&gt; a_j A_j | a_j    其中1&lt;=i,j&lt;=n 且i&lt;&gt;n
</code></pre>
<p>说明：</p>
<ol>
<li>G_n有 2n^2-n 个产生式</li>
<li>G_n有 2^n+n^2+n 个 LR(0) 项集</li>
<li>G_n是 SLR(1) 的</li>
</ol>
<p>关于LR语法分析器的大小，这个分析结果说明了什么？</p>
<h3 id="468"><a class="header" href="#468">4.6.8!</a></h3>
<p>我们说单个项可以看做一个 NFA 的状态，而有效项的集合就是一个 DFA 的状态。对于练习4.2.1的文法 S-&gt;SS+|SS*|a</p>
<ol>
<li>根据“将项看作一个NFA的状态”部分中的规则，画出这个文法的有效的转换图（NFA）</li>
<li>将子集构造算法（算法3.20）应用于在（1）部分构造得到的NFA。得到的DFA和这个文法的LR(0)项集比有什么关系</li>
<li>！！ 说明在任何情况下，将子集构造算法应用于一个文法的有效项的NFA所得到的就是该文法的 LR(0) 项集</li>
</ol>
<h3 id="469"><a class="header" href="#469">4.6.9!</a></h3>
<p>下面是一个二义性的文法</p>
<pre><code>S-&gt;AS|b
A-&gt;SA|a
</code></pre>
<p>构造出这个文法的规范LR(0)项集族。如果我们试图为这个文法构造出一个LR语法分析表，必然会存在某些冲突动作。都有哪些冲突动作？假设我们使用这个语法分析表，并且在出现冲突时不确定地选择一个动作。给出输入abab时所有可能的动作序列</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="47-节的练习"><a class="header" href="#47-节的练习">4.7 节的练习</a></h1>
<h3 id="471"><a class="header" href="#471">4.7.1</a></h3>
<p>为练习 4.2.1 的文法 S -&gt; S S + | S S * | a 构造</p>
<ol>
<li>规范 LR 项集族</li>
<li>LALR 项集族</li>
</ol>
<h4 id="解答-21"><a class="header" href="#解答-21">解答</a></h4>
<p>增广文法G1'如下：</p>
<pre><code>0) S' -&gt; S
1) S -&gt; SS+
2) S -&gt; SS*
3) S -&gt; a
</code></pre>
<p>画出LR(1)自动机如下：</p>
<p><img src="ch04/4.7/./assets/4.7.1.png" alt="4 7 1" /></p>
<p>规范LR(1)项集族参考上图。</p>
<p>针对该项集族，可以合并项集I4和I7，得到项集I47 = [S -&gt; a., a/$]。</p>
<p>于是在规范LR(1)项集族的基础上，删除项集I4和I7，增加项集I47即可得到LALR项集族。</p>
<h3 id="472"><a class="header" href="#472">4.7.2</a></h3>
<p>对练习 4.2.2-1 ~ 4.4.2-7 的各个文法重复练习 4.7.1</p>
<h3 id="-473"><a class="header" href="#-473">! 4.7.3</a></h3>
<p>对练习 4.7.1 的文法，使用算法 4.63，根据该文法的 LR(0) 项集的内核构造出它的 LALR 项集族</p>
<h3 id="-474"><a class="header" href="#-474">! 4.7.4</a></h3>
<p>说明下面的文法</p>
<pre><code>S -&gt; A a | b A c | d c | b d a
A -&gt; d
</code></pre>
<p>是 LALR(1) 的，但不是 SLR(1) 的</p>
<h4 id="解答-22"><a class="header" href="#解答-22">解答</a></h4>
<p>增广文法G'如下：</p>
<pre><code>0) S' -&gt; S
1) S -&gt; Aa
2) S -&gt; bAc
3) S -&gt; dc
4) S -&gt; bda
5) A -&gt; d
</code></pre>
<p>画出LR(0)自动机如下：</p>
<p><img src="ch04/4.7/./assets/4.7.4.png" alt="4 7 4" /></p>
<p>根据上面的LR(0)自动机，可以很快地生成SLR分析表。</p>
<p>注意到在I9状态下，GOTO(I9, c) = I10，于是有Action[9, c] = s10。同时由于[A-&gt;d.] ∈ I9，且Follow(A) = [a, c]，于是有Action[9, c] = r5。此时在Action[9, c] 位置就存在 s/r 冲突，所以文法G'不属于SLR文法。</p>
<p>从理论上讲，I9状态下只需要向前看一个符号p，若p=c则Action[9, c] 填入s10；若p=$则Action[9, c] 填入r5。如此即可避免冲突，所以文法G‘属于是LALR(1)文法。</p>
<p>综上，G'是LALR(1)文法，但不是SLR文法。</p>
<h3 id="-475"><a class="header" href="#-475">! 4.7.5</a></h3>
<p>说明下面的文法</p>
<pre><code>S -&gt; A a | b A c | B c | b B a
A -&gt; d
B -&gt; d
</code></pre>
<p>是 LR(1) 的，但不是 LALR(1) 的</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="chapter-5"><a class="header" href="#chapter-5">Chapter 5</a></h1>
<p>Chapter 5: Syntax-Directed Translation</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="51-节的练习"><a class="header" href="#51-节的练习">5.1 节的练习</a></h1>
<h3 id="511"><a class="header" href="#511">5.1.1</a></h3>
<p>对于图 5-1 中的 SDD，给出下列表达式对应的注释语法分析树</p>
<ol>
<li>(3+4)*(5+6)n</li>
<li>1*2*3*(4+5)n</li>
<li>(9+8*(7+6)+5)*4n</li>
</ol>
<h4 id="解答-23"><a class="header" href="#解答-23">解答</a></h4>
<ol>
<li>
<p>(3+4)*(5+6)n</p>
<p><img src="ch05/5.1/./assets/5.1.1-1.gif" alt="5 1 1-1" /></p>
</li>
<li>
<p>1*2*3*(4+5)n</p>
<p><img src="ch05/5.1/./assets/5.1.1-2.gif" alt="5 1 1-2" /></p>
</li>
</ol>
<h3 id="512"><a class="header" href="#512">5.1.2</a></h3>
<p>扩展图 5-4 中的 SDD，使它可以像图 5-1 所示的那样处理表达式</p>
<h4 id="解答-24"><a class="header" href="#解答-24">解答</a></h4>
<table>
    <thead>
        <tr>
            <th></th>
            <th>产生式</th>
            <th>语法规则</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>1)</td>
            <td>L -> En</td>
            <td>L.val = E.val</td>
        </tr>
        <tr>
            <td>2)</td>
            <td>E -> TE'</td>
            <td>E'.inh = T.val<br/>E.val = E'.syn</td>
        </tr>
        <tr>
            <td>3)</td>
            <td>E' -> +TE_1'</td>
            <td>E_1'.inh = E'.inh + T.val<br/>E'.syn = E_1'.syn</td>
        </tr>
        <tr>
            <td>4)</td>
            <td>E' -> ε</td>
            <td>E'.syn = E'.inh</td>
        </tr>
        <tr>
            <td>5)</td>
            <td>T -> FT'</td>
            <td>T'.inh = F.val<br/>T.val = T'.syn</td>
        </tr>
        <tr>
            <td>6)</td>
            <td>T' -> *FT_1'</td>
            <td>T_1'.inh = T'.inh * F.val<br/>T'.syn = T_1'.syn</td>
        </tr>
        <tr>
            <td>7)</td>
            <td>T' -> ε</td>
            <td>T'.syn = T'.inh</td>
        </tr>
        <tr>
            <td>8)</td>
            <td>F -> (E)</td>
            <td>F.val = E.val</td>
        </tr>
        <tr>
            <td>9)</td>
            <td>F -> digit</td>
            <td>F.val = digit.lexval</td>
        </tr>
    </tbody>
</table>
<h3 id="513"><a class="header" href="#513">5.1.3</a></h3>
<p>使用你在练习 5.1.2 中得到的 SDD，重复练习 5.1.1</p>
<h4 id="解答-25"><a class="header" href="#解答-25">解答</a></h4>
<ol>
<li>
<p>(3+4)*(5+6)n</p>
<p><img src="ch05/5.1/./assets/5.1.3-1.gif" alt="5 1 3-1" /></p>
</li>
<li>
<p>1*2*3*(4+5)n</p>
<p><img src="ch05/5.1/./assets/5.1.3-2.gif" alt="5 1 3-2" /></p>
</li>
</ol>
<div style="break-before: page; page-break-before: always;"></div><h1 id="52-节的练习"><a class="header" href="#52-节的练习">5.2 节的练习</a></h1>
<h3 id="521"><a class="header" href="#521">5.2.1</a></h3>
<p>图 5-7 中的依赖图的全部拓扑顺序有哪些</p>
<h4 id="解答-26"><a class="header" href="#解答-26">解答</a></h4>
<pre><code>[ 1, 2, 3, 4, 5, 6, 7, 8, 9 ],
[ 1, 2, 3, 5, 4, 6, 7, 8, 9 ],
[ 1, 2, 4, 3, 5, 6, 7, 8, 9 ],
[ 1, 3, 2, 4, 5, 6, 7, 8, 9 ],
[ 1, 3, 2, 5, 4, 6, 7, 8, 9 ],
[ 1, 3, 5, 2, 4, 6, 7, 8, 9 ],
[ 2, 1, 3, 4, 5, 6, 7, 8, 9 ],
[ 2, 1, 3, 5, 4, 6, 7, 8, 9 ],
[ 2, 1, 4, 3, 5, 6, 7, 8, 9 ],
[ 2, 4, 1, 3, 5, 6, 7, 8, 9 ]
</code></pre>
<p>算法见 <a href="ch05/5.2/5.2.1.js">5.2.1.js</a></p>
<h3 id="522"><a class="header" href="#522">5.2.2</a></h3>
<p>对于图 5-8 中的 SDD，给出下列表达式对应的注释语法分析树：</p>
<ol>
<li>int a, b , c</li>
<li>float w, x, y, z</li>
</ol>
<h4 id="解答-27"><a class="header" href="#解答-27">解答</a></h4>
<ol>
<li>
<p>int a, b, c</p>
<p><img src="ch05/5.2/./assets/5.2.2-1.gif" alt="5 2 2-1" /></p>
</li>
</ol>
<h3 id="523"><a class="header" href="#523">5.2.3</a></h3>
<p>假设我们有一个产生式 A -&gt; BCD。A, B, C, D 这四个非终结符号都有两个属性，综合属性 s 和继承属性 i。对于下面的每组规则，指出（1）这些规则是否满足 S 属性定义的要求（2）这些规则是否满足 L 属性定义的要求（3）是否存在和这些规则一致的求值过程？</p>
<ol>
<li>A.s = B.i + C.s</li>
<li>A.s = B.i + C.s , D.i = A.i + B.s</li>
<li>A.s = B.s + D.s</li>
<li>! A.s = D.i , B.i = A.s + C.s , C.i = B.s , D.i = B.i + C.i</li>
</ol>
<h4 id="解答-28"><a class="header" href="#解答-28">解答</a></h4>
<ol>
<li>否， ？</li>
<li>否， 是</li>
<li>是， 是</li>
<li>否， 否</li>
</ol>
<h3 id="524-"><a class="header" href="#524-">5.2.4 ！</a></h3>
<p>这个文法生成了含“小数点”的二进制数：</p>
<pre><code>S -&gt; L.L|L
L -&gt; LB|B
B -&gt; 0|1
</code></pre>
<p>设计一个 L 属性的 SDD 来计算 S.val，即输入串的十进制数值。比如，串 101.101 应该被翻译为十进制数 5.625。</p>
<h4 id="解答-29"><a class="header" href="#解答-29">解答</a></h4>
<table>
    <thead>
        <tr>
            <th></th>
            <th>产生式</th>
            <th>语法规则</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>1)</td>
            <td>S -> L_1.L_2</td>
            <td>
                L_1.isLeft = true<br/>
                L_2.isLeft = false<br/>
                S.val = L_1.val + L_2.val
            </td>
        </tr>
        <tr>
            <td>2)</td>
            <td>S -> L</td>
            <td>
                L.isLeft = true<br/>
                S.val = L.val
            </td>
        </tr>
        <tr>
            <td>3)</td>
            <td>L -> L_1B</td>
            <td>
                L_1.isLeft = L.isLeft<br/>
                L.len = L_1.len + 1<br/> 
                L.val = L.isLeft ? L_1.val * 2 + B.val : L_1.val + B.val * 2^(-L.len)
            </td>
        </tr>
        <tr>
            <td>4)</td>
            <td>L -> B</td>
            <td>
                L.len = 1<br/>
                L.val = L.isLeft ? B.val : B.val/2
            </td>
        </tr>  
        <tr>
            <td>5)</td>
            <td>B -> 0</td>
            <td>B.val = 0</td>
        </tr>
        <tr>
            <td>6)</td>
            <td>B -> 1</td>
            <td>B.val = 1</td>
        </tr>
    </tbody>
</table>
<p>其中：</p>
<ul>
<li>isLeft 为继承属性，表示节点是否在小数点的左边</li>
<li>len 为综合属性，表示节点包含的二进制串的长度</li>
<li>val 为综合属性</li>
</ul>
<h3 id="525-"><a class="header" href="#525-">5.2.5 ！！</a></h3>
<p>为练习 5.2.4 中描述的文法和翻译设计一个 S 属性的 SDD。</p>
<h4 id="解答-30"><a class="header" href="#解答-30">解答</a></h4>
<table>
    <thead>
        <tr>
            <th></th>
            <th>产生式</th>
            <th>语法规则</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>1)</td>
            <td>S -> L_1.L_2</td>
            <td>
                S.val = L_1.val +　L_2.val/L_2.f
            </td>
        </tr>
        <tr>
            <td>2)</td>
            <td>S -> L</td>
            <td>
                S.val = L.val
            </td>
        </tr>
        <tr>
            <td>3)</td>
            <td>L -> L_1B</td>
            <td>
                L.val = L_1.val*2 + B.val</br>
                L.f = L_1.f * 2
            </td>
        </tr>
        <tr>
            <td>4)</td>
            <td>L -> B</td>
            <td>
                L.val = B.val</br>
                L.f = 2
            </td>
        </tr>
        <tr>
            <td>5)</td>
            <td>B -> 0</td>
            <td>B.val = 0</td>
        </tr>
        <tr>
            <td>6)</td>
            <td>B -> 1</td>
            <td>B.val = 1</td>
        </tr>
    </tbody>
</table>        
<h3 id="526-"><a class="header" href="#526-">5.2.6 ！！</a></h3>
<p>使用一个自顶向下的语法分析文法上的 L 属性 SDD 来实现算法 3.23。这个算法把一个正则表达式转换为一个 NFA。假设有一个表示任意字符的词法单元 char，并且 char.lexval 是它所表示的字符。你可以假设存在一个函数 new()，该函数范围一个新的状态页就是一个之前尚未被这个函数返回的状态。使用任何方便的表示来描述这个 NFA 的翻译。</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="53-节的练习"><a class="header" href="#53-节的练习">5.3 节的练习</a></h1>
<h3 id="531"><a class="header" href="#531">5.3.1</a></h3>
<p>下面是涉及运算符 + 和整数或浮点运算分量的表达式的文法。区分浮点数的方法是看它有无小数点。</p>
<pre><code>E -&gt; E + T | T
T -&gt; num.num | num
</code></pre>
<ol>
<li>给出一个 SDD 来确定每个项 T 和表达式 E 的类型</li>
<li>扩展这个得到的 SDD，使得它可以把表达式转换成为后缀表达式。使用一个单目运算符 intToFloat 把一个整数转换为相等的浮点数。</li>
</ol>
<h4 id="解答-31"><a class="header" href="#解答-31">解答</a></h4>
<ol>
<li></li>
</ol>
<pre><code>&lt;table&gt;
    &lt;thead&gt;
        &lt;tr&gt;
            &lt;th&gt;&lt;/th&gt;
            &lt;th&gt;产生式&lt;/th&gt;
            &lt;th&gt;语法规则&lt;/th&gt;
        &lt;/tr&gt;
    &lt;/thead&gt;
    &lt;tbody&gt;
        &lt;tr&gt;
            &lt;td&gt;1)&lt;/td&gt;
            &lt;td&gt;E -&gt; E_1 + T&lt;/td&gt;
            &lt;td&gt;E.type = E_1.type === float || T.type === float ? float : int&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;2)&lt;/td&gt;
            &lt;td&gt;E -&gt; T&lt;/td&gt;
            &lt;td&gt;E.type = T.type&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;3)&lt;/td&gt;
            &lt;td&gt;T -&gt; num.num&lt;/td&gt;
            &lt;td&gt;T.type = float&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;4)&lt;/td&gt;
            &lt;td&gt;T -&gt; num&lt;/td&gt;
            &lt;td&gt;T.type = int&lt;/td&gt;
        &lt;/tr&gt;
    &lt;/tbody&gt;
&lt;/table&gt;
</code></pre>
<h3 id="532-"><a class="header" href="#532-">5.3.2 !</a></h3>
<p>给出一个 SDD，将一个带有 + 和 * 的中缀表达式翻译成没有冗余括号的表达式。比如因为两个运算符都是左结合的，并且 * 的优先级高于 +，所以 ((a*(b+c))*(d)) 可翻译为 a*(b+c)*d</p>
<h4 id="解答-32"><a class="header" href="#解答-32">解答</a></h4>
<p>几个属性设置：</p>
<ul>
<li>wrapped: 表达式最外层是否有括号。</li>
<li>precedence: 令 +，*，() 和单 digit 的优先级分别为 0，1，2，3。 如果表达式最外层有括号，则为去掉括号后最后被计算的运算符的优先级，否则为表达式最后被计算的运算符的优先级。</li>
<li>expr: 表达式。</li>
<li>cleanExpr: 去除了冗余括号的表达式。</li>
</ul>
<table>
    <thead>
        <tr>
            <th></th>
            <th>产生式</th>
            <th>语法规则</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>1)</td>
            <td>L -> En</td>
            <td>
                L.cleanExpr = E.wrapped ? E.cleanExpr : E.expr
            </td>
        </tr>
        <tr>
            <td>2)</td>
            <td>E -> E_1 + T</td>
            <td>
                E.wrapped = false<br/>
                E.precedence = 0<br/>
                E.expr = E_1.expr || "+" || T.expr<br/>
                E.cleanExpr = (E_1.wrapped ? E_1.cleanExpr : E_1.expr) || "+" || (T.wrapped ? T.cleanExpr : T.expr)
            </td>
        </tr>
        <tr>
            <td>3)</td>
            <td>E -> T</td>
            <td>
                E.wrapped = T.wrapped<br/>
                E.precedence = T.precedence<br/>
                E.expr = T.expr</br>
                E.cleanExpr = T.cleanExpr
            </td>
        </tr>
        <tr>
            <td>4)</td>
            <td>T -> T_1 * F</td>
            <td>
                T.wrapped = false<br/>
                T.precedence = 1<br/>
                T.expr = T_1.expr || "*" || F.expr<br/>
                T.cleanExpr = (T_1.wrapped && T_1.precedence >= 1 ? T_1.cleanExpr : T_1) || * || (F.wrapped && F.precedence >= 1 ? F.cleanExpr : F.expr)
            </td>
        </tr>
        <tr>
            <td>5)</td>
            <td>T -> F</td>
            <td>
                T.wrapped = F.wrapped<br/>
                T.precedence = F.precedence<br/>
                T.expr = F.expr<br/>
                T.cleanExpr = F.cleanExpr
            </td>
        </tr>
        <tr>
            <td>6)</td>
            <td>F -> (E)</td>
            <td>
                F.wrapped = true<br/>
                F.precedence = E.precedence<br/>
                F.expr = "(" || E.expr || ")"<br/>
                F.cleanExpr = E.expr
            </td>
        </tr>
        <tr>
            <td>7)</td>
            <td>F -> digit</td>
            <td>
                F.wrapped = false<br/>
                F.precedence = 3<br/>
                F.expr = digit<br/>
                F.cleanExpr = digit
            </td>
        </tr>
    </tbody>
</table>
<h3 id="533-"><a class="header" href="#533-">5.3.3 !</a></h3>
<p>给出一个 SDD 对 x*(3*x+x*x) 这样的表达式求微分。表达式中涉及运算符 + 和 * 、变量 x 和常量。假设不进行任何简化，也就是说，比如 3*x 将被翻译为 3*1+0*x。</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="54-节的练习"><a class="header" href="#54-节的练习">5.4 节的练习</a></h1>
<h3 id="541"><a class="header" href="#541">5.4.1</a></h3>
<p>我们在 5.4.2 节中提到可能根据语法分析栈中的 LR 状态来推导出这个状态表示了什么文法符号。我们如何推导这个信息？</p>
<h4 id="解答-33"><a class="header" href="#解答-33">解答</a></h4>
<p>见算法 4.44</p>
<h3 id="542"><a class="header" href="#542">5.4.2</a></h3>
<p>改写下面的 SDT:</p>
<pre><code>A -&gt; A {a} B | A B {b} | 0
B -&gt; B {c} A | B A {d} | 1
</code></pre>
<p>使得基础文法变成非左递归的。</p>
<h3 id="543-"><a class="header" href="#543-">5.4.3 ！</a></h3>
<p>下面的 SDT 计算了一个由 0 和 1 组成的串的值。它把输入的符号串当做正二进制数来解释。</p>
<pre><code>B -&gt; B_1 0 {B.val = 2 * B_1.val}
   | B_1 1 {B.val = 2 * B_1.val + 1}
   | 1 {B.val = 1}
</code></pre>
<p>改写这个 SDT，使得基础文法不再是左递归的，但仍然可以计算出整个输入串的相同的 B.val 的值。</p>
<h4 id="解答-34"><a class="header" href="#解答-34">解答</a></h4>
<p>提取左公因子</p>
<pre><code>B -&gt; B_1 digit {B.val = 2 * B_1.val + digit.val}
   | 1 {B.val = 1}
digit -&gt; 0 {digit.val = 0} 
       | 1 {digit.val = 1}
</code></pre>
<p>在形如 <code>A = A a | b</code> 的左递归产生式中， a 为 <code>digit {B.val = 2 * B_1.val + digit.val}</code>， b 为 <code>1</code></p>
<p>消除左递归后得</p>
<pre><code>B -&gt; 1 {A.i = 1} A
A -&gt; digit {A_1.i = 2 * A.i + digit.val} A_1 {A.val = A_1.val}
   | ε {A.val = A.i}
digit -&gt; 0 {digit.val = 0} 
       | 1 {digit.val = 1}
</code></pre>
<h3 id="544-"><a class="header" href="#544-">5.4.4 ！</a></h3>
<p>为下面的产生式写出一个和例 5.19 类似的 L 属性 SDD。这里的每个产生式表示一个常见的 C 语言那样的控制流结构。你可能需要生成一个三地址语句来跳转到某个标号 L，此时你可以生成语句 goto L。</p>
<ol>
<li>S -&gt; if ( C ) S_1 else S_2</li>
<li>S -&gt; do S_1 while ( C )</li>
<li>S -&gt; '{' L '}'; L -&gt; L S | ε</li>
</ol>
<p>请注意，列表中的任何语句都可能包含一条从它的内部跳转到下一个语句的跳转指令，因此简单地为各个语句按顺序生成代码是不够的。</p>
<h4 id="解答-35"><a class="header" href="#解答-35">解答</a></h4>
<ol>
<li>
<p>S -&gt; if ( C ) S_1 else S_2</p>
<pre><code> L_1 = new()
 C.false = L_1  
 S_1.next = S.next
 S.code = C.code || S_1.code || label || L_1 || S_2.code                              
</code></pre>
</li>
<li>
<p>S -&gt; do S_1 while ( C )</p>
<pre><code>L_1 = new()
C.true = L_1
S.code = label || L_1 || S_1.code || C.code
</code></pre>
</li>
</ol>
<h3 id="545"><a class="header" href="#545">5.4.5</a></h3>
<p>按照例 5.19 的方法，把在练习 5.4.4 中得到的各个 SDD 转换成一个 SDT。</p>
<h4 id="解答-36"><a class="header" href="#解答-36">解答</a></h4>
<ol>
<li>
<p>S -&gt; if ( C ) S_1 else S_2</p>
<pre><code> S -&gt; if (     {new L_1; C.false = L_1}   
      C )      {S_1.next = S.next}
      S_1 else
      S_2      {S.code = C.code || S_1.code || label || L_1 || S_2.code}
</code></pre>
</li>
<li>
<p>S -&gt; do S_1 while ( C )</p>
<pre><code>S -&gt; do           {new L_1} 
     S_1 while (  {C.true = L_1}
     C )          {S.code = label || L_1 || S_1.code || C.code}
</code></pre>
</li>
</ol>
<h3 id="546"><a class="header" href="#546">5.4.6</a></h3>
<p>修改图 5.25 中的 SDD，使它包含一个综合属性 B.le，即一个方框的长度。两个方框并列后得到的方框的长度是这两个方框的长度和。然后把你的新规则加入到图 5.26 中 SDT 的合适位置上。</p>
<h3 id="547"><a class="header" href="#547">5.4.7</a></h3>
<p>修改图 5.25 中的 SDD，使它包含上标，用方框之间的运算符 sup 表示。如果方框 B_2 是方框 B_1 的一个上标，那么将 B_2 的基线放在 B_1 的基线上方，两条基线的距离是 0.6 乘以 B_1 的大小。把新的产生式和规则加入到图 5.26 的 SDT 中去。</p>
<h4 id="546-和-547-的解答"><a class="header" href="#546-和-547-的解答">5.4.6 和 5.4.7 的解答</a></h4>
<pre><code>1) S -&gt; B               B.ps = 10
                        B.wd = 
                        
2) S -&gt; B_1 B_2         B_1.ps = B.ps
                        B_2.ps = B.ps
                        B.wd = B_1.wd + B_2.wd
                        B.ht = max(B_1.ht, B_2.ht)
                        B.dp = max(B_1.dp, B_2.dp)

3) B -&gt; B_1 sub B_2     B_1.ps = B.ps
                        B_2.ps = 0.7 * B.ps
                        B.wd = B_1.wd + B_2.wd
                        B.ht = max(B_1.ht, B_2.ht - 0.25 * B.ps)
                        B.dp = max(B_1.dp, B_2.dp + 0.25 * B.ps)

4) B -&gt; B_1 sup B_2     B_1.ps = B.ps
                        B_2.ps = 0.6 * B.ps
                        B.wd = B_1.wd + B_2.wd
                        B.ht = max(B_1.ht, B_2.ht + 0.6 * B.ps)
                        B.dp = max(B_1.dp, B_2.dp - 0.6 * B.ps)    

5) B -&gt; ( B_1 )         B_1.ps = B.ps
                        B.wd = B_1.wd
                        B.ht = B_1.ht
                        B.dp = B_1.dp

6) B -&gt; text            B.wd = getWd(B.ps, text.lexval)
                        B.ht = getHt(B.ps, text.lexval)
                        B.dp = getDp(B.ps, text.lexval)
</code></pre>
<div style="break-before: page; page-break-before: always;"></div><h1 id="55-节的练习"><a class="header" href="#55-节的练习">5.5 节的练习</a></h1>
<h3 id="551"><a class="header" href="#551">5.5.1</a></h3>
<p>按照 5.5.1 节的风格，将练习 5.4.4 中得到的每个 SDD 实现为递归下降的语法分析器。</p>
<h3 id="552"><a class="header" href="#552">5.5.2</a></h3>
<p>按照 5.5.2 节的风格，将练习 5.4.4 中得到的每个 SDD 实现为递归下降的语法分析器。</p>
<h3 id="553"><a class="header" href="#553">5.5.3</a></h3>
<p>按照 5.5.3 节的风格，将练习 5.4.4 中得到的每个 SDD 和一个 LL 语法分析器一起实现。它们应该边扫描输入边生成代码。</p>
<h3 id="554"><a class="header" href="#554">5.5.4</a></h3>
<p>按照 5.5.3 节的风格，将练习 5.4.4 中得到的每个 SDD 和一个 LL 语法分析器一起实现，但是代码（或者指向代码的指针）存放在栈中。</p>
<h3 id="555"><a class="header" href="#555">5.5.5</a></h3>
<p>按照 5.5.4 节的风格，将练习 5.4.4 中得到的每个 SDD 和一个 LR 语法分析器一起实现。</p>
<h3 id="556"><a class="header" href="#556">5.5.6</a></h3>
<p>按照 5.5.1 节 的风格实现练习 5.2.4 中得到的 SDD。按照 5.5.2 节的风格得到的实现和这个实现相比有什么不同吗？</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="chapter-6"><a class="header" href="#chapter-6">Chapter 6</a></h1>
<p>Chapter 6: Intermediate-Code Generation</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="61-节的练习"><a class="header" href="#61-节的练习">6.1 节的练习</a></h1>
<h3 id="为下面的表达式构造-dag"><a class="header" href="#为下面的表达式构造-dag">为下面的表达式构造 DAG</a></h3>
<pre><code>((x+y)-((x+y)*(x-y)))+((x+y)*(x-y))
</code></pre>
<h4 id="解答-37"><a class="header" href="#解答-37">解答</a></h4>
<p><img src="ch06/6.1/./assets/6.1.1.gif" alt="6.1.1" /></p>
<h3 id="为下列表达式构造-dag且指出他们每个子表达式的值编码假定--是左结合的"><a class="header" href="#为下列表达式构造-dag且指出他们每个子表达式的值编码假定--是左结合的">为下列表达式构造 DAG，且指出他们每个子表达式的值编码。假定 + 是左结合的。</a></h3>
<ol>
<li>a+b+(a+b)</li>
<li>a+b+a+b</li>
<li>a+a+(a+a+a+(a+a+a+a))</li>
</ol>
<h4 id="解答-38"><a class="header" href="#解答-38">解答</a></h4>
<ol>
<li>
<p>a+b+(a+b)</p>
<p><img src="ch06/6.1/./assets/6.1.2-1.gif" alt="6 1 2-1" /></p>
<table>
     <tbody>
         <tr>
             <td>1</td>
             <td>id</td>
             <td>a</td>
             <td></td>
         </tr>
         <tr>
             <td>2</td>
             <td>id</td>
             <td>b</td>
             <td></td>
         </tr>
         <tr>
             <td>3</td>
             <td>+</td>
             <td>1</td>
             <td>2</td>
         </tr>
         <tr>
             <td>4</td>
             <td>+</td>
             <td>3</td>
             <td>3</td>
         </tr>
     </tbody>
 </table>
</li>
<li>
<p>a+b+a+b</p>
<p><img src="ch06/6.1/./assets/6.1.2-2.gif" alt="6 1 2-2" /></p>
<table>
     <tbody>
         <tr>
             <td>1</td>
             <td>id</td>
             <td>a</td>
             <td></td>
         </tr>
         <tr>
             <td>2</td>
             <td>id</td>
             <td>b</td>
             <td></td>
         </tr>
         <tr>
             <td>3</td>
             <td>+</td>
             <td>1</td>
             <td>2</td>
         </tr>
         <tr>
             <td>4</td>
             <td>+</td>
             <td>3</td>
             <td>1</td>
         </tr>
         <tr>
             <td>5</td>
             <td>+</td>
             <td>4</td>
             <td>2</td>
         </tr>
     </tbody>
 </table>
</li>
<li>
<p>a+a+(a+a+a+(a+a+a+a))</p>
<p><img src="ch06/6.1/./assets/6.1.2-3.gif" alt="6 1 2-3" /></p>
<table>
     <tbody>
         <tr>
             <td>1</td>
             <td>id</td>
             <td>a</td>
             <td></td>
         </tr>
         <tr>
             <td>2</td>
             <td>+</td>
             <td>1</td>
             <td>1</td>
         </tr>
         <tr>
             <td>3</td>
             <td>+</td>
             <td>2</td>
             <td>1</td>
         </tr>
         <tr>
             <td>4</td>
             <td>+</td>
             <td>3</td>
             <td>1</td>
         </tr>
         <tr>
             <td>5</td>
             <td>+</td>
             <td>3</td>
             <td>4</td>
         </tr>
         <tr>
             <td>6</td>
             <td>+</td>
             <td>2</td>
             <td>5</td>
         </tr>
     </tbody>
 </table>
</li>
</ol>
<div style="break-before: page; page-break-before: always;"></div><h1 id="62-节的练习"><a class="header" href="#62-节的练习">6.2 节的练习</a></h1>
<h3 id="621"><a class="header" href="#621">6.2.1</a></h3>
<p>将算数表达式 a+-(b+c) 翻译成</p>
<ol>
<li>抽象语法树</li>
<li>四元式序列</li>
<li>三元式序列</li>
<li>间接三元式序列</li>
</ol>
<h4 id="解答-39"><a class="header" href="#解答-39">解答</a></h4>
<ol>
<li>
<p>抽象语法树</p>
<p><img src="ch06/6.2/./assets/6.2.1.gif" alt="6 2 1" /></p>
</li>
<li>
<p>四元式序列</p>
<table>
     <thead>
         <tr>
             <th></th>
             <th>op</th>
             <th>arg1</th>
             <th>arg2</th>
             <th>result</th>
         </tr>
     </thead>
     <tbody>
         <tr>
             <td>0</td>
             <td>+</td>
             <td>b</td>
             <td>c</td>
             <td>t1</td>
         </tr>
         <tr>
             <td>1</td>
             <td>minus</td>
             <td>t1</td>
             <td></td>
             <td>t2</td>
         </tr>
         <tr>
             <td>2</td>
             <td>+</td>
             <td>a</td>
             <td>t2</td>
             <td>t3</td>
         </tr>
     </tbody>
 </table>
</li>
<li>
<p>三元式序列</p>
<table>
     <thead>
         <tr>
             <th></th>
             <th>op</th>
             <th>arg1</th>
             <th>arg2</th>
         </tr>
     </thead>
     <tbody>
         <tr>
             <td>0</td>
             <td>+</td>
             <td>b</td>
             <td>c</td>
         </tr>
         <tr>
             <td>1</td>
             <td>minus</td>
             <td>(0)</td>
             <td></td>
         </tr>
         <tr>
             <td>2</td>
             <td>+</td>
             <td>a</td>
             <td>(1)</td>
         </tr>
     </tbody>
 </table>
</li>
<li>
<p>间接三元式序列</p>
<table>
     <thead>
         <tr>
             <th></th>
             <th>op</th>
             <th>arg1</th>
             <th>arg2</th>
         </tr>
     </thead>
     <tbody>
         <tr>
             <td>0</td>
             <td>+</td>
             <td>b</td>
             <td>c</td>
         </tr>
         <tr>
             <td>1</td>
             <td>minus</td>
             <td>(0)</td>
             <td></td>
         </tr>
         <tr>
             <td>2</td>
             <td>+</td>
             <td>a</td>
             <td>(1)</td>
         </tr>
     </tbody>
 </table>
<table>
     <thead>
         <tr>
             <th></th>
             <th>instruction</th>
         </tr>
     </thead>
     <tbody>
         <tr>
             <td>0</td>
             <td>(0)</td>
         </tr>
         <tr>
             <td>1</td>
             <td>(1)</td>
         </tr>
         <tr>
             <td>2</td>
             <td>(2)</td>
         </tr>
     </tbody>
 </table>
</li>
</ol>
<h4 id="参考"><a class="header" href="#参考">参考</a></h4>
<ul>
<li><a href="http://jpkc.nwpu.edu.cn/jp2005/20/kcwz/wlkc/wlkc/05/5_3_2.htm">间接三元式更详细的讲解</a></li>
</ul>
<h3 id="622"><a class="header" href="#622">6.2.2</a></h3>
<p>对下列赋值语句重复练习 6.2.1</p>
<ol>
<li>a = b[i] + c[j]</li>
<li>a[i] = b*c - b*d</li>
<li>x = f(y+1) + 2</li>
<li>x = *p + &amp;y</li>
</ol>
<h4 id="解答-40"><a class="header" href="#解答-40">解答</a></h4>
<ol>
<li>
<p>a = b[i] + c[j]</p>
<ul>
<li>
<p>四元式</p>
<pre><code>  0) =[]   b    i    t1
  1) =[]   c    j    t2
  2) +     t1   t2   t3
  3) =     t3        a  
</code></pre>
</li>
<li>
<p>三元式</p>
<pre><code>  0) =[]   b    i
  1) =[]   c    j
  2) +     (0)  (1)
  3) =     a    (2)  
</code></pre>
</li>
<li>
<p>间接三元式</p>
<pre><code>  0) =[]   b    i
  1) =[]   c    j
  2) +     (0)  (1)
  3) =     a    (2)  
  
  0） 
  1）
  2）
  3）
</code></pre>
</li>
</ul>
</li>
<li>
<p>a[i] = b*c - b*d</p>
<ul>
<li>
<p>四元式</p>
<pre><code>  0) *    b    c    t1
  1) *    b    d    t2
  2) -    t1   t2   t3
  3) []=  a    i    t4
  4) =    t3        t4
</code></pre>
</li>
<li>
<p>三元式</p>
<pre><code>  0) *    b    c
  1) *    b    d
  2) -    (0)  (1)
  3) []=  a    i
  4) =    (3)  (2)
</code></pre>
</li>
<li>
<p>间接三元式</p>
<pre><code>  0) *    b    c
  1) *    b    d
  2) -    (0)  (1)
  3) []=  a    i
  4) =    (3)  (2)
  
  0)
  1)
  2)
  3)
  4)
</code></pre>
</li>
</ul>
</li>
<li>
<p>x = f(y+1) + 2</p>
<ul>
<li>
<p>四元式</p>
<pre><code>  0) +        y    1    t1
  1) param    t1
  2) call     f    1    t2
  3) +        t2    2   t3
  4) =        t3        x
</code></pre>
</li>
<li>
<p>三元式</p>
<pre><code>  0) +        y     1
  1) param    (0)
  2) call     f     1
  3) +        (2)   2
  4) =        x     (3)
</code></pre>
</li>
<li>
<p>间接三元式</p>
<pre><code>  0) +        y     1
  1) param    (0)
  2) call     f     1
  3) +        (2)   2
  4) =        x     (3)
  
  0)
  1)
  2)
  3)
  4)
</code></pre>
</li>
</ul>
</li>
</ol>
<h4 id="参考-1"><a class="header" href="#参考-1">参考</a></h4>
<ul>
<li><a href="http://www.mec.ac.in/resources/notes/notes/compiler/module5/intermediate.htm">数组元素的取值和赋值</a></li>
</ul>
<h3 id="623-"><a class="header" href="#623-">6.2.3 !</a></h3>
<p>说明如何对一个三地址代码序列进行转换，使得每个被定值的变量都有唯一的变量名。</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="63-节的练习"><a class="header" href="#63-节的练习">6.3 节的练习</a></h1>
<h3 id="631"><a class="header" href="#631">6.3.1</a></h3>
<p>确定下列声明序列中各个标识符的类型和相对地址。</p>
<pre><code>float x;
record {float x; float y;} p;
record {int tag; float x; float y;} q;
</code></pre>
<h4 id="解答-41"><a class="header" href="#解答-41">解答</a></h4>
<p>SDT</p>
<pre><code>S -&gt;                  {top = new Evn(); offset = 0;}
     D 
D -&gt; T id;            {top.put(id.lexeme, T.type, offset);
                       offset += T.width}
     D1
D -&gt; ε
T -&gt; int              {T.type = interget; T.width = 4;}
T -&gt; float            {T.type = float; T.width = 8;}
T -&gt; record '{'
                      {Evn.push(top), top = new Evn();
                       Stack.push(offset), offset = 0;}
     D '}'            {T.type = record(top); T.width = offset;
                       top = Evn.top(); offset = Stack.pop();}
</code></pre>
<p>标识符类型和相对地址</p>
<pre><code>line id      type        offset   Evn

  1) x       float       0        1

  2) x       float       0        2
  2) y       float       8        2
  2) p       record()    8        1

  3) tag     int         0        3
  3) x       float       4        3
  3) y       float       12       3
  3) q       record()    24       1     
</code></pre>
<h3 id="632-"><a class="header" href="#632-">6.3.2 !</a></h3>
<p>将图 6-18 对字段名的处理方法扩展到类和单继承的层次结构。</p>
<ol>
<li>给出类 Evn 的一个实现。该实现支持符号表链，使得子类可以重定义一个字段名，也可以直接引用某个超类中的字段名。</li>
<li>给出一个翻译方案，该方案能够为类中的字段分配连续的数据区域，这些字段中包含继承而来的域。继承而来的字段必须保持在对超类进行存储分配时获得的相对地址。</li>
</ol>
<div style="break-before: page; page-break-before: always;"></div><h1 id="64-节的练习"><a class="header" href="#64-节的练习">6.4 节的练习</a></h1>
<h3 id="641"><a class="header" href="#641">6.4.1</a></h3>
<p>向图 6-19 的翻译方案中加入对应于下列产生式的规则：</p>
<ol>
<li>E -&gt; E1 * E2</li>
<li>E -&gt; +E1</li>
</ol>
<h4 id="解答-42"><a class="header" href="#解答-42">解答</a></h4>
<pre><code>产生式           语义规则

E -&gt; E1 * E2    { E.addr = new Temp();
                  E.code = E1.code || E2.code ||
                           gen(E.addr '=' E1.addr '*' E2.addr); }
                         
   | +E1        { E.addr = E1.addr;
                  E.code = E1.code; }
</code></pre>
<h3 id="642"><a class="header" href="#642">6.4.2</a></h3>
<p>使用图 6-20 的增量式翻译方案重复练习 6.4.1</p>
<h4 id="解答-43"><a class="header" href="#解答-43">解答</a></h4>
<pre><code>产生式           语义规则

E -&gt; E1 * E2    { E.addr =  new Temp();
                  gen(E.addr '=' E1.addr '*' E2.addr; }
                         
   | +E1        { E.addr = E1.addr; }
</code></pre>
<h3 id="643"><a class="header" href="#643">6.4.3</a></h3>
<p>使用图 6-22 的翻译方案来翻译下列赋值语句：</p>
<ol>
<li>x = a[i] + b[j]</li>
<li>x = a[i][j] + b[i][j]</li>
<li>! x = a[b[i][j]][c[k]]</li>
</ol>
<h4 id="解答-44"><a class="header" href="#解答-44">解答</a></h4>
<ol>
<li>
<p>x = a[i] + b[j]</p>
<p>语法分析树:</p>
<p><img src="ch06/6.4/./assets/6.4.3-1.gif" alt="6 4 3-1" /></p>
<p>三地址代码</p>
<pre><code> t_1 = i * awidth
 t_2 = a[t_1]
 t_3 = j * bwidth
 t_4 = b[t_3]
 t_5 = t_2 + t_4
 x = t_5
</code></pre>
</li>
<li>
<p>x = a[i][j] + b[i][j]</p>
<p>语法分析树：</p>
<p><img src="ch06/6.4/./assets/6.4.3-2.gif" alt="6 4 3-2" /></p>
<p>三地址代码：</p>
<pre><code> t_1 = i * ai_width
 t_2 = j * aj_width
 t_3 = t_1 + t_2
 t_4 = a[t_3]
 t_5 = i * bi_width
 t_6 = j * bj_width
 t_7 = t_5 + t_6
 t_8 = b[t_7]
 t_9 = t_4 + t_8
 x = t_9
</code></pre>
</li>
<li>
<p>! x = a[b[i][j]][c[k]]</p>
</li>
</ol>
<h3 id="644-"><a class="header" href="#644-">6.4.4 !</a></h3>
<p>修改图 6-22 的翻译方案，使之适合 Fortran 风格的数据引用，也就是说 n 维数组的引用为 id[E1, E2, …, En]</p>
<h4 id="解答-45"><a class="header" href="#解答-45">解答</a></h4>
<p>仅需修改 L 产生式（同图 6-22 一样，未考虑消除左递归）</p>
<pre><code>L -&gt; id[A]  { L.addr = A.addr; 
              global.array = top.get(id.lexeme); }
              
A -&gt; E      { A.array = global.array;
              A.type = A.array.type.elem;
              A.addr = new Temp();
              gen(A.addr '=' E.addr '*' A.type.width; }
              
A -&gt; A1,E   { A.array = A1.array;
              A.type = A1.type.elem;
              t = new Temp();
              A.addr = new Temp();
              gen(t '=' E.addr '*' A.type.length);
              gen(A.addr '=' A1.addr '+' t); }
</code></pre>
<h4 id="注意-1"><a class="header" href="#注意-1">注意</a></h4>
<p>令 a 表示一个 i*j 的数组，单个元素宽度为 w</p>
<pre><code>a.type = array(i, array(j, w))
a.type.length = i
a.type.elem = array(j, w)
</code></pre>
<h3 id="645"><a class="header" href="#645">6.4.5</a></h3>
<p>将公式 6.7 推广到多维数据上，并指出哪些值可以被存放到符号表中并用来计算偏移量。考虑下列情况：</p>
<ol>
<li>一个二维数组 A，按行存放。第一维的下标从 l_1 到 h_1，第二维的下标从 l_2 到 h_2。单个数组元素的宽度为 w。</li>
<li>其他条件和 1 相同，但是采用按列存放方式。</li>
<li>！一个 k 维数组 A，按行存放，元素宽度为 w，第 j 维的下标从 l_j 到 h_j。</li>
<li>！其他条件和 3 相同，但是采用按列存放方式。</li>
</ol>
<h4 id="解答-46"><a class="header" href="#解答-46">解答</a></h4>
<p>令 n_i 为第 i 维数组的元素个数，计算公式：n_i = h_i - l_i + 1</p>
<pre><code>3. A[i_1]]…[i_k] = base + 
                   (
                       (i_1 - l_1) * n_2 * … * n_k +
                       … + 
                       (i_k-1 - l_k-1) * n_k +
                       (i_k - l_k)
                   ) * w
                 
4. A[i_1]]…[i_k] = base + 
                   (
                       (i_1 - l_1) +
                       (i_2 - l_2) * n_1 + 
                       … +
                       (i_k - l_k) * n_k-1 * n_k-2 * … * n_1
                   ) * w
</code></pre>
<h3 id="646"><a class="header" href="#646">6.4.6</a></h3>
<p>一个按行存放的整数数组 A[i, j] 的下标 i 的范围为 1~10，下标 j 的范围为 1~20。每个整数占 4 个字节。假设数组 A 从 0 字节开始存放，请给出下列元素的位置：</p>
<ol>
<li>A[4, 5]</li>
<li>A[10, 8]</li>
<li>A[3, 17]</li>
</ol>
<h4 id="解答-47"><a class="header" href="#解答-47">解答</a></h4>
<p>计算公式：((i-1) * 20 + (j-1)) * 4</p>
<ol>
<li>(3 * 20 + 4) * 4 = 256</li>
<li>(9 * 20 + 7) * 4 = 748</li>
<li>(2 * 20 + 16) * 4 = 224</li>
</ol>
<h3 id="647"><a class="header" href="#647">6.4.7</a></h3>
<p>假定 A 是按列存放的，重复练习 6.4.6</p>
<h4 id="解答-48"><a class="header" href="#解答-48">解答</a></h4>
<p>计算公式：((j-1) * 10 + (j-1)) * 4</p>
<ol>
<li>(4 * 10 + 3) * 4 = 172</li>
<li>(7 * 10 + 9) * 4 = 316</li>
<li>(16 * 10 + 2) * 4 = 648</li>
</ol>
<h3 id="648"><a class="header" href="#648">6.4.8</a></h3>
<p>一个按行存放的实数型数组 A[i, j, k] 的下标 i 的范围为 1~4，下标 j 的范围为 0~4，且下标 k 的范围为 5~10。每个实数占 8 个字节。假设数组 A 从 0 字节开始存放，计算下列元素的位置：</p>
<ol>
<li>A[3, 4, 5]</li>
<li>A[1, 2, 7]</li>
<li>A[4, 3, 9]</li>
</ol>
<h4 id="解答-49"><a class="header" href="#解答-49">解答</a></h4>
<p>计算公式：((i-1) * 5 * 6 + j * 6 + (k-5)) * 8</p>
<ol>
<li>((3-1) * 5 * 6 + 4 * 6 + (5-5)) * 8 = 672</li>
<li>((1-1) * 5 * 6 + 2 * 6 + (7-5)) * 8 = 112</li>
<li>((4-1) * 5 * 6 + 3 * 6 + (9-5)) * 8 = 896</li>
</ol>
<h3 id="649"><a class="header" href="#649">6.4.9</a></h3>
<p>假定 A 是按列存放的，重复练习 6.4.8</p>
<h4 id="解答-50"><a class="header" href="#解答-50">解答</a></h4>
<p>计算公式：((i-1) + j * 4 + (k-5) * 5 * 4) * 8</p>
<ol>
<li>((3-1) + 4 * 4 + (5-5) * 5 * 4) * 8 = 144</li>
<li>((1-1) + 2 * 4 + (7-5) * 5 * 4) * 8 = 384</li>
<li>((4-1) + 3 * 4 + (9-5) * 5 * 4) * 8 = 760</li>
</ol>
<div style="break-before: page; page-break-before: always;"></div><h1 id="65-节的练习"><a class="header" href="#65-节的练习">6.5 节的练习</a></h1>
<h3 id="651"><a class="header" href="#651">6.5.1</a></h3>
<p>假定图 6-26 中的函数 widen 可以处理图 6-25a 的层次结构中的所有类型，翻译下列表达式。假定 c 和 d 是字符类型，s 和 t 是短整型， i 和 j 为整型， x 是浮点型。</p>
<ol>
<li>x = s + c</li>
<li>i = s + c</li>
<li>x = (s + c) * (t + d)</li>
</ol>
<h4 id="解答-51"><a class="header" href="#解答-51">解答</a></h4>
<ol>
<li>
<p>x = s + c</p>
<pre><code> t1 = (int) s
 t2 = (int) c
 t3 = t1 + t2
 x = (float) t3
</code></pre>
</li>
<li>
<p>i = s + c</p>
<pre><code> t1 = (int) s
 t2 = (int) c
 i = t1 + t2
</code></pre>
</li>
<li>
<p>x = (s + c) * (t + d)</p>
<pre><code> t1 = (int) s
 t2 = (int) c
 t3 = t1 + t2
 t4 = (int) t
 t5 = (int) d
 t6 = t4 + t5
 t7 = t3 + t6
 x = (float) t7
</code></pre>
</li>
</ol>
<h3 id="652"><a class="header" href="#652">6.5.2</a></h3>
<p>像 Ada 中那样，我们假设每个表达式必须具有唯一的类型，但是我们根据一个子表达式本身只能推导出一个可能类型的集合。也就是说，将函数 E1 应用于参数 E2（文法产生式为 E -&gt; E1(E2)）有如下规则：</p>
<pre><code>E.type = {t | 对 E2.type 中的某个 s, s -&gt; t 在 E1.type 中}
</code></pre>
<p>描述一个可以确定每个字表达式的唯一类型的 SDD。它首先使用属性 type，按照自底向上的方式综合得到一个可能类型的集合。在确定了整个表达式的唯一类型之后，自顶向下地确定属性 unique 的值，整个属性表示各子表达式的类型。</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="66-节的练习"><a class="header" href="#66-节的练习">6.6 节的练习</a></h1>
<h3 id="661"><a class="header" href="#661">6.6.1</a></h3>
<p>在图 6-36 的语法制导定义中添加处理下列控制流构造的规则：</p>
<ol>
<li>一个 repeat 语句：repeat S while B</li>
<li>！一个 for 循环语句：for (S1; B; S2) S3</li>
</ol>
<h4 id="解答-52"><a class="header" href="#解答-52">解答</a></h4>
<pre><code>Production                  Syntax Rule

S -&gt; repeat S1 while B      S1.next = newlabel()
                            B.true = newlabel()
                            B.false = S.next
                            S.code = label(B.true) || S1.code
                                || label(S1.next) || B.code
                                
S -&gt; for (S1; B; S2) S3     S1.next = newlabel()
                            B.true = newlabel()
                            B.false = S.next
                            S2.next = S1.next
                            S3.next = newlabel()
                            S.code = S1.code
                                || lable(S1.next) || B.code
                                || lable(B.true) || S3.code
                                || label(S3.next) || S2.code
                                || gen('goto', S1.next)
</code></pre>
<h3 id="662"><a class="header" href="#662">6.6.2</a></h3>
<p>现代计算机试图在同一个时刻执行多条指令，其中包括各种分支指令。因此，当计算机投机性地预先执行某个分支，但实际控制流却进入另一个分支时，付出的代价是很大的。因此我们希望尽可能地减少分支数量。请注意，在图 6-35c 中 while 循环语句的实现中，每个迭代有两个分支：一个是从条件 B 进入到循环体中，另一个分支跳转回 B 的代码。基于尽量减少分支的考虑，我们通常更倾向于将 while(B) S 当作 if(B) {repeat S until !(B)} 来实现。给出这种翻译方法的代码布局，并修改图 6-36 中 while 循环语句的规则。</p>
<h4 id="解答-53"><a class="header" href="#解答-53">解答</a></h4>
<pre><code>Production               Syntax Rule

S -&gt; if(B) {             B.true = newlabel()    
        repeat S1        B.false = S.next            
        until !(B)       S1.next = newlabel()
     }                   S.code = B.code
                             || label(B.true) || S1.code
                             || label(S1.next) || B.code
</code></pre>
<h3 id="663"><a class="header" href="#663">6.6.3！</a></h3>
<p>假设 C 中存在一个异或运算。按照图 6-37 的风格写出这个运算符的代码生成规则。</p>
<h4 id="解答-54"><a class="header" href="#解答-54">解答</a></h4>
<p>B1 ^ B2 等价于 !B1 &amp;&amp; B2 || B1 &amp;&amp; !B2 (运算符优先级 ! &gt; &amp;&amp; &gt; ||)</p>
<pre><code>Production      Syntax Rule

B -&gt; B1 ^ B2    B1.true = newlabel()
                B1.false = newlabel()
                
                B2.true = B.true
                B2.false = B1.true
                
                b3 = newboolean()
                b3.code = B1.code
                b3.true = newlabel()
                b3.false = B.false
                
                b4 = newboolean()
                b4.code = B2.code
                b4.true = B.false
                b4.false = B.true
                
                S.code = B1.code
                    || label(B1.false) || B2.code
                    || label(B1.true) || b3.code
                    || label(b3.true) || b4.code
</code></pre>
<h3 id="664"><a class="header" href="#664">6.6.4</a></h3>
<p>使用 6.6.5 节中介绍的避免 goto 语句的翻译方案，翻译下列表达式：</p>
<ol>
<li>if (a==b &amp;&amp; c==d || e==f) x == 1</li>
<li>if (a==b || c==d || e==f) x == 1</li>
<li>if (a==b || c==d &amp;&amp; e==f) x == 1</li>
</ol>
<h4 id="解答-55"><a class="header" href="#解答-55">解答</a></h4>
<ol>
<li>
<p>if (a==b &amp;&amp; c==d || e==f) x == 1</p>
<pre><code>     ifFalse a==b goto L3 
     if c==d goto L2
 L3: ifFalse e==f goto L1
 L2: x == 1
 L1:
</code></pre>
</li>
<li>
<p>if (a==b || c==d || e==f) x == 1</p>
<pre><code>     if a==b goto L2
     if c==d goto L2
     ifFalse e==f goto L1
 L2: x==1
 L1:
</code></pre>
</li>
<li>
<p>if (a==b || c==d &amp;&amp; e==f) x == 1</p>
<pre><code>     if a==b goto L2
     ifFalse c==d goto L1
     ifFalse e==f goto L1
 L2: x==1
 L1:
</code></pre>
</li>
</ol>
<h3 id="665"><a class="header" href="#665">6.6.5</a></h3>
<p>基于图 6-36 和图 6-37 中给出的语法制导定义，给出一个翻译方案。</p>
<h3 id="666"><a class="header" href="#666">6.6.6</a></h3>
<p>使用类似于图 6-39 和图 6-40 中的规则，修改图 6-36 和图 6-37 的语义规则，使之允许控制流穿越。</p>
<h4 id="解答-56"><a class="header" href="#解答-56">解答</a></h4>
<p>仅补充完毕书中未解答部分</p>
<pre><code>Production              Syntax Rule
                    
S -&gt; if(B) S1 else S2   B.true = fall
                        B.false = newlabel()
                        S1.next = S.next
                        S2.next = S.next
                        S.code = B.code 
                            || S1.code
                            || gen('goto' S1.next)
                            || label(B.false) || S2.code
                            
S -&gt; while(B) S1        begin = newlabel()
                        B.true = fall
                        B.false = S.next
                        S1.next = begin
                        S.code = label(begin) || B.code
                            || S1.code
                            || gen('goto' begin)
                            
S -&gt; S1 S2              S1.next = fall
                        S2.next = S.next
                        S.code = S1.code || S2.code
                        
B -&gt; B1 &amp;&amp; B2           B1.true = fall
                        B1.false = if B.false == fall
                                   then newlabel()
                                   else B.false
                        B2.true = B.true
                        B2.false = B.false
                        B.code = if B.false == fall
                                 then B1.code || B2.code || label(B1.false)
                                 else B1.code || B2.code
</code></pre>
<h3 id="667"><a class="header" href="#667">6.6.7！</a></h3>
<p>练习 6.6.6 中的语义规则产生了一些不必要的标号。修改图 6-36 中语句的规则，使之只创建必要的标号。你可以使用特殊符号 deferred 来表示还没有创建的一个标号。你的语义规则必须能生成类似于例 6.21 的代码。</p>
<h3 id="668"><a class="header" href="#668">6.6.8！！</a></h3>
<p>6.6.5 节中讨论了如何使用穿越代码来尽可能减少生成的中间代码中跳转指令的数据。然而，它并没有充分考虑将一个条件替换为它的补的方法，例如将 <code>if a &lt; b goto L1; goto L2</code> 替换成 <code>ifFalse a &gt;= b goto L2; goto L1</code>。给出语法制导定义，它在需要时可以利用这种替换方法。</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="67-节的练习"><a class="header" href="#67-节的练习">6.7 节的练习</a></h1>
<h3 id="671"><a class="header" href="#671">6.7.1</a></h3>
<p>使用图 6-43 中的翻译方案翻译下列表达式。给出每个子表达式的 truelist 和 falselist。你可以假设第一条被生成的指令的地址是 100.</p>
<ol>
<li>a==b &amp;&amp; (c==d || e==f)</li>
<li>(a==b || c==d) || e==f</li>
<li>(a==b &amp;&amp; c==d) &amp;&amp; e==f</li>
</ol>
<h4 id="解答-57"><a class="header" href="#解答-57">解答</a></h4>
<ol>
<li>
<p>a==b &amp;&amp; (c==d || e==f)</p>
<p><img src="ch06/6.7/./assets/6.7.1-1.gif" alt="6 7 1-1" /></p>
</li>
</ol>
<h3 id="672"><a class="header" href="#672">6.7.2</a></h3>
<h4 id="解答-58"><a class="header" href="#解答-58">解答</a></h4>
<ol>
<li>E3.false = i1</li>
<li>S2.next = i7</li>
<li>E4.false = i7</li>
<li>S1.next = i3</li>
<li>E2.true = i3</li>
</ol>
<h3 id="673"><a class="header" href="#673">6.7.3</a></h3>
<p>当使用图 6-46 中的翻译方案对图 6-47 进行翻译时，我们为每条语句创建 S.next 列表。一开始是赋值语句 S1, S2, S3，然后逐步处理越来越大的 if 语句，if-else 语句，while 语句和语句块。在图 6-47 中有 5 个这种类型的结构语句：</p>
<ul>
<li>S4: while (E3) S1</li>
<li>S5: if(E4) S2</li>
<li>S6: 包含 S5 和 S3 的语句块</li>
<li>S7: if(E2) S4 else S6</li>
<li>S8: 整个程序</li>
</ul>
<p>对于这些结构语句，我们可以通过一个规则用其他的 Sj.next 列表以及程序中的表达式的列表 Ek.true 和 Ek.false 构造出 Si.next。给出计算下列 next 列表的规则：</p>
<ol>
<li>S4.next</li>
<li>S5.next</li>
<li>S6.next</li>
<li>S7.next</li>
<li>S8.next</li>
</ol>
<h4 id="解答-59"><a class="header" href="#解答-59">解答</a></h4>
<p>(该题解答不是很肯定)</p>
<ol>
<li>S4.next = S3.next</li>
<li>S5.next = S2.next</li>
<li>S6.next = S3.next</li>
<li>S7.next = S3.next</li>
<li>S8.next = E1.false</li>
</ol>
<div style="break-before: page; page-break-before: always;"></div><h1 id="chapter-7"><a class="header" href="#chapter-7">Chapter 7</a></h1>
<p>Chapter 7: Run-Time Environments</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="exercises-for-section-72"><a class="header" href="#exercises-for-section-72">Exercises for Section 7.2</a></h1>
<h3 id="721"><a class="header" href="#721">7.2.1</a></h3>
<p>Suppose that the program of Fig.7.2 uses a partition function that always picks a[m] as the separator v. Also, when the array a[m], … , a[n] is reordered, assume that the order is preserved as much as possible. That is, first come all the elements less than v, in their original order, then all elements equal to v, and finally all elements greater than v, in their original order.</p>
<ol>
<li>Draw the activation tree when the numbers 9,8,7,6,5,4,3,2,1 are sorted.</li>
<li>What is the largest number of activation records that ever appear together
on the stack?</li>
</ol>
<h4 id="answer-52"><a class="header" href="#answer-52">Answer</a></h4>
<ol>
<li>
<p>Draw the activation tree when the numbers 9,8,7,6,5,4,3,2,1 are sorted.</p>
<p><img src="https://f.cloud.github.com/assets/340282/1266950/7194fe12-2ca0-11e3-919f-2e6870287e71.gif" alt="7 2 1-1" /></p>
</li>
<li>
<p>What is the largest number of activation records that ever appear together
on the stack?</p>
<p>9</p>
</li>
</ol>
<h3 id="722"><a class="header" href="#722">7.2.2</a></h3>
<p>Repeat Exercise 7.2.1 when the initial order of the numbers
is 1,3,5,7,9,2,4,6,8.</p>
<h3 id="723"><a class="header" href="#723">7.2.3</a></h3>
<p>In Fig. 7.9 is C code to compute Fibonacci numbers recur­sively. Suppose that the activation record for f includes the following elements in order: (return value, argument n, local s, local t); there will normally be other elements in the activation record as well. The questions below assume that the initial call is f(5).</p>
<pre><code>int f(int n) {
    int t, s;
    if (n &lt; 2) return 1;
    s = f(n-1);
    t = f(n-2);
    return s+t;
}

Figure 7.9: Fibonacci program for Exercise 7.2.3
</code></pre>
<ol>
<li>Show the complete activation tree. </li>
<li>What dose the stack and its activation records look like the first time f(1) is about to return?</li>
<li>! What does the stack and its activation records look like the fifth time f(1) is about to return?</li>
</ol>
<h4 id="answer-53"><a class="header" href="#answer-53">Answer</a></h4>
<ol>
<li>
<p>Show the complete activation tree. </p>
<p><img src="https://f.cloud.github.com/assets/340282/1266985/e78871c4-2ca2-11e3-831c-501caa1fecde.gif" alt="7 2 3-1" /></p>
</li>
<li>
<p>What dose the stack and its activation records look like the first time f(1) is about to return?</p>
<p><img src="https://f.cloud.github.com/assets/340282/1267036/7d762abc-2ca5-11e3-8ad9-c62bdc30bc7f.gif" alt="7 2 3-2" /></p>
</li>
<li>
<p>! What does the stack and its activation records look like the fifth time f(1) is about to return?</p>
<p><img src="https://f.cloud.github.com/assets/340282/1267034/6196935e-2ca5-11e3-9d4d-c9e4aa861842.gif" alt="7 2 3-3" /></p>
</li>
</ol>
<h3 id="724"><a class="header" href="#724">7.2.4</a></h3>
<p>Here is a sketch of two C functions f and g:</p>
<pre><code>int f(int x){int i;...return i+1;...}
int g(int y) {int j;...f(j+1). ..}
</code></pre>
<p>That is, function g calls f. Draw the top of the stack, starting with the acti­vation record for g, after g calls f, and f is about to return. You can consider only return values, parameters, control links, and space for local variables; you do not have to consider stored state or temporary or local values not shown in the code sketch. However, you should indicate:</p>
<ol>
<li>Which function creates the space on the stack for each element?</li>
<li>Which function writes the value of each element?</li>
<li>To which activation record does the element belong?</li>
</ol>
<h4 id="answer-54"><a class="header" href="#answer-54">Answer</a></h4>
<p><img src="https://f.cloud.github.com/assets/340282/1267088/836d0550-2ca8-11e3-923d-757450951b13.gif" alt="7 2 4" /></p>
<h3 id="725"><a class="header" href="#725">7.2.5</a></h3>
<p>In a language that passes parameters by reference, there is a function f(x, y) that does the following:</p>
<pre><code>x = x + 1; 
y = y + 2;
return x+y;
</code></pre>
<p>If a is assigned the value 3, and then f(a, a) is called, what is returned? </p>
<h4 id="answer-55"><a class="header" href="#answer-55">Answer</a></h4>
<pre><code>x = x + 1  -&gt;  a = a + 1  -&gt;  now a is 4
y = y + 2  -&gt;  a = a + 2  -&gt;  now a is 6
x + y  -&gt;  a + a  -&gt;  6 + 6  -&gt;  12
</code></pre>
<p>f(a, a) is 12</p>
<h3 id="726"><a class="header" href="#726">7.2.6</a></h3>
<p>The C function f is defined by:</p>
<pre><code>int f(int x, *py, **ppz) {
    **ppz += 1;
    *py += 2;
    x += 3;
    return x+y+z;
}
</code></pre>
<p>Variable a is a pointer to b; variable b is a pointer to c, and c is an integer currently with value 4. If we call f(c, b, a) , what is returned?</p>
<h4 id="answer-56"><a class="header" href="#answer-56">Answer</a></h4>
<p>f(c, b, a) is 21</p>
<p>view <a href="ch07/7.2/7.2.6.c">source code</a></p>
<p>mind that c is passed by value, so the process is:</p>
<pre><code>sentence        x in f()   x out of f()  *py    **ppz
            
**ppz += 1;     4          5             5      5
*py += 2;       4          7             7      7
x += 3;         7          7             7      7
</code></pre>
<div style="break-before: page; page-break-before: always;"></div><h1 id="exercises-for-section-73"><a class="header" href="#exercises-for-section-73">Exercises for Section 7.3</a></h1>
<h3 id="731"><a class="header" href="#731">7.3.1</a></h3>
<p>In Fig. 7.15 is a ML function main that computes Fibonacci numbers in a nonstandard way. Function fibO will compute the nth Fibonacci number for any n &gt;= O. Nested within in is fib1, which computes the nth Fibonacci number on the assumption n &gt;= 2, and nested within fib1 is fib2, which assumes n &gt;= 4. Note that neither fib1 nor fib2 need to check for the basis cases. Show the stack of activation records that result from a call to main, up until the time that the first call (to fibO(1)) is about to return. Show the access link in each of the activation records on the stack.</p>
<pre><code>fun main() {
    let
        fun fibO(n) 
            let
                fun fib1(n) =   
                    let
                        fun fib2(n) = fib1(n-l) + fib1(n-2)  
                    in
                        if n &gt;= 4 then fib2(n)
                        else fibO(n-l) + fibO(n-2)  
                    end
            in
                if n &gt;= 2 then fib1(n) else 1
            end  
    in
        fibO(4)  
    end ;
</code></pre>
<p>Figure 7.15: Nested functions computing Fibonacci numbers</p>
<h4 id="answer-57"><a class="header" href="#answer-57">Answer</a></h4>
<p>activation tree:</p>
<p><img src="https://f.cloud.github.com/assets/340282/1274670/bccd7442-2dc0-11e3-9f3f-7c8122b10240.gif" alt="7 3 1-activation-tree" /></p>
<p>activation stack when first call to fib0(1) is about to return:</p>
<p><img src="https://f.cloud.github.com/assets/340282/1274682/718986ea-2dc2-11e3-8e80-a450f8cb17d3.gif" alt="7 3 1-activation-stack" /></p>
<h3 id="732"><a class="header" href="#732">7.3.2</a></h3>
<p>Suppose that we implement the functions of Fig. 7.15 using a display. Show the display at the moment the first call to fibO(1) is about to return. Also, indicate the saved display entry in each of the activation records on the stack at that time.
￼</p>
<h4 id="answer-58"><a class="header" href="#answer-58">Answer</a></h4>
<p><img src="https://f.cloud.github.com/assets/340282/1274690/d564dbc8-2dc3-11e3-828e-4740db58898d.gif" alt="7 3 2" /></p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="74"><a class="header" href="#74">7.4</a></h1>
<div style="break-before: page; page-break-before: always;"></div><h1 id="exercises-for-section-75"><a class="header" href="#exercises-for-section-75">Exercises for Section 7.5</a></h1>
<h3 id="751"><a class="header" href="#751">7.5.1</a></h3>
<p>What happens to the reference counts of the objects in Fig. 7.19 if:</p>
<ol>
<li>The pointer from A to B is deleted.</li>
<li>The pointer from X to A is deleted.</li>
<li>The node C is deleted.</li>
</ol>
<p><img src="https://f.cloud.github.com/assets/340282/1276364/72fc7390-2e60-11e3-8816-a5a535a9d67a.png" alt="A network of objects" /></p>
<p>Figure 7.19: A network of objects</p>
<h4 id="answer-59"><a class="header" href="#answer-59">Answer</a></h4>
<ol>
<li>
<p>The pointer from A to B is deleted.</p>
<p><img src="https://f.cloud.github.com/assets/340282/1276399/35528b7e-2e65-11e3-8056-8c54e0dae1c8.gif" alt="7 5 1-1" /></p>
</li>
<li>
<p>The pointer from X to A is deleted.</p>
<p><img src="https://f.cloud.github.com/assets/340282/1276400/42f0b468-2e65-11e3-940a-e7f7b4cce5da.gif" alt="7 5 1-2" /></p>
</li>
<li>
<p>The node C is deleted.</p>
<p><img src="https://f.cloud.github.com/assets/340282/1276401/4c9b1d14-2e65-11e3-9ae7-d4dd4f75bd40.gif" alt="7 5 1-3" /></p>
</li>
</ol>
<h3 id="752"><a class="header" href="#752">7.5.2</a></h3>
<p>What happens to reference counts when the pointer from A to D in Fig. 7.20 is deleted?</p>
<p><img src="https://f.cloud.github.com/assets/340282/1276366/87f56964-2e60-11e3-9d88-fd56f7e2d3f4.png" alt="Another network of objects" /></p>
<p>Figure 7.20: Another network of objects</p>
<h4 id="answer-60"><a class="header" href="#answer-60">Answer</a></h4>
<p><img src="https://f.cloud.github.com/assets/340282/1276406/eac449f2-2e65-11e3-8e4c-def958552810.gif" alt="7 5 2" /></p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="exercises-for-section-76"><a class="header" href="#exercises-for-section-76">Exercises for Section 7.6</a></h1>
<h3 id="761"><a class="header" href="#761">7.6.1</a></h3>
<p>Show the steps of a mark-and-sweep garbage collector on</p>
<ol>
<li>Fig. 7.19 with the pointer A to B deleted.</li>
<li>Fig. 7.19 with the pointer A to C deleted.</li>
<li>Fig. 7.20 with the pointer A to D deleted.</li>
<li>Fig. 7.20 with the object B deleted.</li>
</ol>
<h4 id="answer-61"><a class="header" href="#answer-61">Answer</a></h4>
<ol>
<li>
<p>Fig. 7.19 with the pointer A to B deleted. </p>
<pre><code> before:     A.reached =  … = I.reached = 0  
             Unscanned = []
 

 line1:      A.reached = 1
             Unscanned.push(A)
            
 line2~7:
 
     loop1:  Unscanned.shift()
             C.reached = 1
             Unscanned.push( C )
             
     loop2:  Unscanned.shift()
             F.reached = 1
             Uncanned.push(F)
             
     loop3:  Unscanned.shift()
             H.reached = 1
             Uncanned.push(H)
             
     loop4:  Unscanned.shift()
             I.reached = 1
             Uncanned.push(I)
             
     loop5:  Unscanned.shift()
             G.reached = 1
             Uncanned.push(G)
             
     loop6:  Unscanned.shift()
             E.reached = 1
             Uncanned.push(E)
             
     loop7:  Unscanned.shift()
             // no more object add to list Unscanned
             // now it is empty, loop end
             
 line8:      Free = []
 
 line9~11:   Free = [B, D]
             A.reached = C.reached = E.reached = … = I.reached = 0
</code></pre>
</li>
</ol>
<h3 id="762"><a class="header" href="#762">7.6.2</a></h3>
<p>The Baker mark-and-sweep algorithm moves objects among four lists: Free, Unreached, Unscanned, and Scanned. For each of the object networks of Exercise 7.6.1, indicate for each object the sequence of lists on which it finds itself from just before garbage collection begins until just after it finishes.</p>
<h4 id="answer-62"><a class="header" href="#answer-62">Answer</a></h4>
<ol>
<li>
<p>Fig. 7.19 with the pointer A to B deleted.</p>
<pre><code> line1:      Free = [] // assume it is empty
             Unreached = [A, B, C, D, E, F, G, H, I]
             Unscanned = []
             Scanned = []

 line2:      Unscanned = [A]
             Unreached = [B, C, D, E, F, G, H, I]
             
 line3~7:
 
     loop1:  Scanned = [A]
             Unscanned = [C]
             Unreached = [B, D, E, F, G, H, I]
     
     loop2:  Scanned = [A, C]
             Unscanned = [F]
             Unreached = [B, D, E, G, H, I]
     
     loop3:  Scanned = [A, C, F]
             Unscanned = [H]
             Unreached = [B, D, E, G, I]
     
     loop4:  Scanned = [A, C, F, H]
             Unscanned = [I]
             Unreached = [B, D, E, G]
     
     loop5:  Scanned = [A, C, F, H, I]
             Unscanned = [G]
             Unreached = [B, D, E]
     
     loop6:  Scanned = [A, C, F, H, I, G]
             Unscanned = [E]
             Unreached = [B, D]
     
     loop7:  Scanned = [A, C, F, H, I, G, E]
             Unscanned = []
             Unreached = [B, D]
 
 line8:      Free = [B, D]
 
 line9:      Unreached = [A, C, F, H, I, G, E]
</code></pre>
</li>
</ol>
<h3 id="763"><a class="header" href="#763">7.6.3</a></h3>
<p>Suppose we perform a mark-and-compact garbage collection on each of the networks of Exercise 7.6.1. Also, suppose that</p>
<ol>
<li>Each object has size 100 bytes, and</li>
<li>Initially, the nine objects in the heap are arranged in alphabetical order,
starting at byte 0 of the heap.</li>
</ol>
<p>What is the address of each object after garbage collection?</p>
<h4 id="answer-63"><a class="header" href="#answer-63">Answer</a></h4>
<ol>
<li>
<p>Fig. 7.19 with the pointer A to B deleted. </p>
<pre><code> A(0), C(100), E(200), F(300), G(400), H(500), I(600)
</code></pre>
</li>
</ol>
<h3 id="764"><a class="header" href="#764">7.6.4</a></h3>
<p>Suppose we execute Cheney's copying garbage collection al­gorithm on each of the networks of Exercise 7.6.1. Also, suppose that </p>
<ol>
<li>Each object has size 100 bytes,</li>
<li>The unscanned list is managed as a queue, and when an object has more than one pointer, the reached objects are added to the queue in alpha­ betical order, and</li>
<li>The From semispace starts at location 0, and the To semispace starts at location 10,000.</li>
</ol>
<p>What is the value of NewLocation(o) for each object o that remains after garbage collection?</p>
<h4 id="answer-64"><a class="header" href="#answer-64">Answer</a></h4>
<ol>
<li>
<p>Fig. 7.19 with the pointer A to B deleted. </p>
<pre><code> A(10000), C(10100), F(10200), H(10300), I(10400), G(10500), E(10600)
</code></pre>
</li>
</ol>
<div style="break-before: page; page-break-before: always;"></div><h1 id="exercises-for-section-77"><a class="header" href="#exercises-for-section-77">Exercises for Section 7.7</a></h1>
<h3 id="771"><a class="header" href="#771">7.7.1</a></h3>
<p>Suppose that the network of objects from Fig.7.20 is managed by an incremental algorithm that uses the four lists Unreached, Unscanned, Scanned, and Free, as in Baker's algorithm. To be specific, the Unscanned list is managed as a queue, and when more than one object is to be placed on this list due to the scanning of one object, we do so in alphabetical order. Suppose also that we use write barriers to assure that no reachable object is made garbage. Starting with A and B on the Unscanned list, suppose the following events occur:</p>
<ol>
<li>A is scanned.</li>
<li>The pointer A -&gt; D is rewritten to be A -&gt; H.</li>
<li>B is scanned.</li>
<li>D is scanned.</li>
<li>The pointer B -&gt; C is rewritten to be B -&gt; I.</li>
</ol>
<p>Simulate the entire incremental garbage collection, assuming no more pointers are rewritten. Which objects are garbage? Which objects are placed on the Free list?</p>
<h4 id="answer-65"><a class="header" href="#answer-65">Answer</a></h4>
<ol start="0">
<li>
<p>init</p>
<p><img src="https://f.cloud.github.com/assets/340282/1276366/87f56964-2e60-11e3-9d88-fd56f7e2d3f4.png" alt="Another network of objects" /></p>
<pre><code> Free = []
 Unreached = [C, D, E, F, G, H, I]
 Uscanned = [A, B]
 Scanned = []
</code></pre>
</li>
<li>
<p>A is scanned.</p>
<pre><code> Unreached = [C, F, G, H, I]
 Uscanned = [B, D, E]
 Scanned = [A]
</code></pre>
</li>
<li>
<p>The pointer A -&gt; D is rewritten to be A -&gt; H.</p>
<p><img src="https://f.cloud.github.com/assets/340282/1313843/079b394a-3263-11e3-8659-a54bcc5ea3d8.gif" alt="7 7 1-1" /></p>
<pre><code> Unreached = [C, F, G, I]
 Uscanned = [B, D, E, H]
 Scanned = [A]
</code></pre>
</li>
<li>
<p>B is scanned.</p>
<pre><code> Unreached = [F, G, I]
 Uscanned = [D, E, H, C]
 Scanned = [A, B]
</code></pre>
</li>
<li>
<p>D is scanned.</p>
<pre><code> Unreached = [F, G, I]
 Uscanned = [E, H, C]
 Scanned = [A, B, D]
</code></pre>
</li>
<li>
<p>The pointer B -&gt; C is rewritten to be B -&gt; I.</p>
<p><img src="https://f.cloud.github.com/assets/340282/1313847/144a01e4-3263-11e3-8037-b09e2c3b03f4.gif" alt="7 7 1-2" /></p>
<pre><code> Unreached = [F, G]
 Uscanned = [E, H, C, I]
 Scanned = [A, B, D]
</code></pre>
</li>
<li>
<p>E is scanned.</p>
<pre><code> Unreached = [F, G]
 Uscanned = [H, C, I]
 Scanned = [A, B, D, E]
</code></pre>
</li>
<li>
<p>H is scanned.</p>
<pre><code> Unreached = [F, G]
 Uscanned = [C, I]
 Scanned = [A, B, D, E, H]
</code></pre>
</li>
<li>
<p>C is scanned.</p>
<pre><code> Unreached = [F, G]
 Uscanned = [I]
 Scanned = [A, B, D, E, H, C]
</code></pre>
</li>
<li>
<p>I is scanned.</p>
<pre><code>Unreached = [F, G]
Uscanned = []
Scanned = [A, B, D, E, H, C, I]
</code></pre>
</li>
<li>
<p>end</p>
<pre><code>Free = [F, G]
Unreached = [A, B, D, E, H, C, I]
Unscanned = []
Scanned = []
</code></pre>
</li>
</ol>
<p>so, <code>[C, D, F, G]</code> is garbage, Free list is <code>[F, G]</code>.</p>
<h3 id="772"><a class="header" href="#772">7.7.2</a></h3>
<p>Repeat Exercise 7.7.1 on the assumption that </p>
<ol>
<li>Events (2) and (5) are interchanged in order.</li>
<li>Events (2) and (5) occur before (1), (3), and (4).</li>
</ol>
<h4 id="answer-66"><a class="header" href="#answer-66">Answer</a></h4>
<ol>
<li>
<p>Events (2) and (5) are interchanged in order.</p>
<p>omit</p>
</li>
<li>
<p>Events (2) and (5) occur before (1), (3), and (4).</p>
<ol start="0">
<li>
<p>init</p>
<p><img src="https://f.cloud.github.com/assets/340282/1276366/87f56964-2e60-11e3-9d88-fd56f7e2d3f4.png" alt="Another network of objects" /></p>
<pre><code> Free = []
 Unreached = [C, D, E, F, G, H, I]
 Uscanned = [A, B]
 Scanned = []
</code></pre>
</li>
<li>
<p>The pointer A -&gt; D is rewritten to be A -&gt; H.</p>
<p><img src="https://f.cloud.github.com/assets/340282/1313843/079b394a-3263-11e3-8659-a54bcc5ea3d8.gif" alt="7 7 1-1" /></p>
<pre><code> Unreached = [C, D, E, F, G, I]
 Uscanned = [A, B, H]
</code></pre>
</li>
<li>
<p>The pointer B -&gt; C is rewritten to be B -&gt; I.</p>
<p><img src="https://f.cloud.github.com/assets/340282/1313847/144a01e4-3263-11e3-8037-b09e2c3b03f4.gif" alt="7 7 1-2" /></p>
<pre><code> Unreached = [C, D, E, F, G]
 Uscanned = [A, B, H, I]
</code></pre>
</li>
<li>
<p>A is scanned.</p>
<pre><code> Unreached = [C, D, F, G]
 Unscanned = [B, H, I, E]
 Scanned = [A]
</code></pre>
</li>
<li>
<p>B is scanned.</p>
<pre><code> Unreached = [C, D, F, G]
 Unscanned = [H, I, E]
 Scanned = [A, B]
</code></pre>
</li>
<li>
<p>H is scanned.</p>
<pre><code> Unreached = [C, D, F, G]
 Unscanned = [I, E]
 Scanned = [A, B, H]
</code></pre>
</li>
<li>
<p>I is scanned.</p>
<pre><code> Unreached = [C, D, F, G]
 Unscanned = [E]
 Scanned = [A, B, H, I]
</code></pre>
</li>
<li>
<p>E is scanned.</p>
<pre><code> Unreached = [C, D, F, G]
 Unscanned = []
 Scanned = [A, B, H, I, E]
</code></pre>
</li>
<li>
<p>end</p>
<pre><code> Free = [C, D, F, G]
 Unreached = [A, B, H, I, E]
 Unscanned = []
 Scanned = []
</code></pre>
</li>
</ol>
<p>so, <code>[C, D, F, G]</code> is garbage, Free list also is <code>[C, D, F, G]</code>.</p>
</li>
</ol>
<h3 id="773"><a class="header" href="#773">7.7.3</a></h3>
<p>Suppose the heap consists of exactly the nine cars on three trains shown in Fig. 7.30 (i.e., ignore the ellipses). Object o in car 11 has references from cars 12, 23, and 32. When we garbage collect car 11, where might o wind up?</p>
<h4 id="answer-67"><a class="header" href="#answer-67">Answer</a></h4>
<pre><code>if any room in trains 2 and 3
    o can go in some existing car of either trains 2 and 3.
else
    o can go in a new, last car of either trains 2 and 3. 
</code></pre>
<h3 id="774"><a class="header" href="#774">7.7.4</a></h3>
<p>Repeat Exercise 7.7.3 for the cases that o has</p>
<ol>
<li>Only references from cars 22 and 31.</li>
<li>No references other than from car 11.</li>
</ol>
<h4 id="answer-68"><a class="header" href="#answer-68">Answer</a></h4>
<ol>
<li>
<p>Only references from cars 22 and 31.</p>
<p>The same with Exercise 7.7.3.</p>
</li>
<li>
<p>No references other than from car 11.</p>
<pre><code> if there is room in car 12
     o can go in car 12
 else if there is room in other cars of train 1
     o can go in any car has room
 else
     o can go in a new, last car of train 1
</code></pre>
</li>
</ol>
<h3 id="775"><a class="header" href="#775">7.7.5</a></h3>
<p>Suppose the heap consists of exactly the nine cars on three trains shown in Fig. 7.30 (i.e., ignore the ellipses). We are currently in panic mode. Object o1 in car 11 has only one reference, from object o2 in car 12. That reference is rewritten. When we garbage collect car 11, what could happen to o1?</p>
<h4 id="answer-69"><a class="header" href="#answer-69">Answer</a></h4>
<p>It is not important which train we move it to, as long as it is not the first train？</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="chapter-8"><a class="header" href="#chapter-8">Chapter 8</a></h1>
<p>Chapter 8: Code Generation</p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="exercises-for-section-82"><a class="header" href="#exercises-for-section-82">Exercises for Section 8.2</a></h1>
<h3 id="821"><a class="header" href="#821">8.2.1</a></h3>
<p>Generate code for the following three-address statements assuming all variables are stored in memory locations.</p>
<ol>
<li>x = 1</li>
<li>x = a</li>
<li>x = a + 1</li>
<li>x = a + b</li>
<li>The two statements
<ul>
<li>x = b * c</li>
<li>y = a + x</li>
</ul>
</li>
</ol>
<h4 id="answer-70"><a class="header" href="#answer-70">answer</a></h4>
<pre><code>1.  LD R1, #1
    ST x, R1

2.  LD R1, a
    ST x, R1

3.  LD R1, a
    ADD R1, R1, #1
    ST x, R1

4.  LD R1, a
    LD R2, b
    ADD R1, R1, R2
    ST x, R1

5.  LD R1, b
    LD R2, c
    MUL R1, R1, R2
    LD R3, a
    ADD R3, R3, R1
    ST y, R3
</code></pre>
<p>Note：第 5 小题，可以在生成的汇编码第三行后插入 <code>ST x, R1</code> 和 <code>LD R1, x</code> 两句，这两句属于冗余代码（redundant store-load）。使用简易代码生成策略很容易生成这种冗余代码，慢是慢一些但是也是正确的，有专门处理这种问题的优化（redundant store-load elimination），所以生不生成在这题的答案里感觉都行。</p>
<h3 id="822"><a class="header" href="#822">8.2.2</a></h3>
<p>Generate code for the following three-address statements assuming a and b are arrays whose elements are 4-byte values.</p>
<ol>
<li>
<p>The four-statement sequence</p>
<pre><code> x = a[i]
 y = b[j]
 a[i] = y
 b[j] = x
</code></pre>
</li>
<li>
<p>The three-statement sequence</p>
<pre><code> x = a[i]
 y = b[i]
 z = x * y
</code></pre>
</li>
<li>
<p>The three-statement sequence</p>
<pre><code> x = a[i]
 y = b[x]
 a[i] = y
</code></pre>
</li>
</ol>
<h4 id="answer-71"><a class="header" href="#answer-71">answer</a></h4>
<pre><code>1.  LD R1, i
    MUL R1, R1, #4
    LD R2, a(R1)
    LD R3, j
    MUL R3, R3, #4
    LD R4, b(R3)
    ST a(R1), R4
    ST b(R3), R2

2.  LD R1, i
    MUL R1, R1, #4
    LD R2, a(R1)
    LD R1, b(R1)
    MUL R1, R2, R1
    ST z, R1

3.  LD R1, i
    MUL R1, R1, #4
    LD R2, a(R1)
    MUL R2, R2, #4
    LD R2, b(R2)
    ST a(R1), R2
</code></pre>
<h3 id="823"><a class="header" href="#823">8.2.3</a></h3>
<p>Generate code for the following three-address sequence assuming that p and q are in memory locations:</p>
<pre><code>y = *q
q = q + 4
*p = y
p = p + 4
</code></pre>
<h4 id="answer-72"><a class="header" href="#answer-72">answer</a></h4>
<pre><code>LD R1, q
LD R2, 0(R1)
ADD R1, R1, #4
ST q, R1
LD R1, p
ST 0(R1), R2
ADD R1, R1, #4
ST p, R1
</code></pre>
<h3 id="824"><a class="header" href="#824">8.2.4</a></h3>
<p>Generate code for the following sequence assuming that x, y, and z are in memory locations:</p>
<pre><code>    if x &lt; y goto L1
    z = 0
    goto L2
L1: z = 1
</code></pre>
<h4 id="answer-73"><a class="header" href="#answer-73">answer</a></h4>
<pre><code>    LD R1, x
    LD R2, y
    SUB R1, R1, R2
    BLTZ R1, L1
    LD R1, #0
    ST z, R1
    BR L2
L1: LD R1, #1
    ST z, R1
</code></pre>
<p>Note：实际生成代码时会把标签对应到具体的数字地址上，但这小节还没到那一步，把原本题目里的标签名拿来随便写写就好啦。</p>
<h3 id="825"><a class="header" href="#825">8.2.5</a></h3>
<p>Generate code for the following sequence assuming that n is in a memory location:</p>
<pre><code>    s = 0
    i = 0
L1: if i &gt; n goto L2
    s = s + i
    i = i + 1
    goto L1
L2:
</code></pre>
<h4 id="answer-74"><a class="header" href="#answer-74">answer</a></h4>
<pre><code>Long version:

    LD R1, #0
    ST s, R1
    ST i, R1
L1: LD R1, i
    LD R2, n
    SUB R2, R1, R2
    BGTZ R2, L2
    LD R2, s
    ADD R2, R2, R1
    ST s, R2
    ADD R1, R1, #1
    ST i, R1
    BR L1
L2:

Short version:

    LD R2, #0
    LD R1, R2
    LD R3, n
L1: SUB R4, R1, R3
    BGTZ R4, L2
    ADD R2, R2, R1
    ADD R1, R1, #1
    BR L1
L2:
</code></pre>
<p>Note：短版本的优化 1）消除冗余存-读 2）循环不变代码外提 3）然后外加寄存器分配</p>
<h3 id="826"><a class="header" href="#826">8.2.6</a></h3>
<p>Determine the costs of the following instruction sequences:</p>
<pre><code>1.  LD R0, y
    LD R1, z
    ADD R0, R0, R1
    ST x, R0

2.  LD R0, i
    MUL R0, R0, 8
    LD R1, a(R0)
    ST b, R1

3.  LD R0, c
    LD R1, i
    MUL R1, R1, 8
    ST a(R1),R0

4.  LD R0, p
    LD R1, 0(R0)
    ST x, R1

5.  LD R0, p
    LD R1, x
    ST 0(R0), R1

6.  LD R0, x
    LD R1, y
    SUB R0, R0, R1
    BLTZ *R3, R0
</code></pre>
<h4 id="answer-75"><a class="header" href="#answer-75">answer</a></h4>
<ol>
<li>2 + 2 + 1 + 2 = 7</li>
<li>2 + 2 + 2 + 2 = 8</li>
<li>2 + 2 + 2 + 2 = 8</li>
<li>2 + 2 + 2 = 6</li>
<li>2 + 2 + 2 = 6</li>
<li>2 + 2 + 1 + 1 = 6</li>
</ol>
<p>Note：这本书用的指令集没明确定义所有指令的细节，但看起来所谓用变量名来指定内存地址实际上隐含着这些变量是静态分配的假设，也就是说在真正生成完的指令里这些变量名都会被替换为它们对应的数字形式的地址常量，而地址存在指令后的一个额外的word里，这就算多一单位的开销。</p>
<hr />
<h3 id="note"><a class="header" href="#note">Note</a></h3>
<ol>
<li>
<p>很明显本节内容写得非常随意，推荐数字常量是应该都加#前缀的，除了放在地址里用。比如 <code>LD R1, #1</code> 和 <code>ADD R1, R1, #1</code>。</p>
</li>
<li>
<p>本书中 Ri 表示第 i 号寄存器。</p>
<ol>
<li>
<p>在翻译成汇编码的过程中，是可以随意指定 i 的值（比如 R3, R4, R1000）呢还是会有某种限制？</p>
<p>回答：现在暂时随意。等后面说寄存器个数有限制的时候再考虑有限制的情况。</p>
</li>
<li>
<p>另外，如果代码中所示的 R1 在后面的代码中用不着了，那么新的值是不是可以被加载到 R1 中？如果可以的话，如何知道之前的 R1 用不着了？</p>
<p>回答：可以覆盖。至于如何知道前面的值死了就要看 def-use 链。这是优化的重要问题。例如9.2.5小节讲 live variable 就跟这个有关。</p>
</li>
</ol>
</li>
<li>
<p>b = a[i] 对应的汇编码：</p>
<pre><code>LD R1, i
MUL R1, R1, 8
LD R2, a(R1)
...
</code></pre>
<p>其中 a 为什么不需要先 load 到寄存器？</p>
<p>回答：这里隐含一个假设：变量是静态分配存储的。后面涉及不是静态变量的时候情况会有变化。</p>
</li>
</ol>
<div style="break-before: page; page-break-before: always;"></div><h1 id="exercises-for-section-83"><a class="header" href="#exercises-for-section-83">Exercises for Section 8.3</a></h1>
<h3 id="831"><a class="header" href="#831">8.3.1</a></h3>
<p>Generate code for the following three-address statements assuming stack
allocation where register SP points to the top of the stack.</p>
<pre><code>call p
call q
return
call r
return
return
</code></pre>
<h4 id="answer-76"><a class="header" href="#answer-76">Answer</a></h4>
<pre><code>100:  LD SP, #stackStart
108： ADD SP, SP, #psize
116:  ST *SP, #132
124:  BR pStart
132:  SUB SP, SP, #psize
140:  ADD SP, SP, #qsize
148:  ST *SP, #164
156:  BR qStart
164:  SUB SP, SP, #qsize
172:  BR **SP
</code></pre>
<h3 id="832"><a class="header" href="#832">8.3.2</a></h3>
<p>Generate code for the following three-address statements assuming stack
allocation where register SP points to the top of the stack.</p>
<ol>
<li>x = 1</li>
<li>x=a</li>
<li>x = a + 1</li>
<li>x = a+b</li>
<li>The two statements
<ul>
<li>x = b * c</li>
<li>y = a + x</li>
</ul>
</li>
</ol>
<h3 id="833"><a class="header" href="#833">8.3.3</a></h3>
<p>Generate code for the following three-address statements again assuming stack
allocation and assuming a and b are arrays whose elements are 4-byte values.</p>
<ol>
<li>
<p>The four-statement sequence</p>
<pre><code>x = a[i]
y = b[j]
a[i] = y
b[j] = x
</code></pre>
</li>
<li>
<p>The three-statement sequence</p>
<pre><code>x = a[i]
y = b[i]
z = x * y
</code></pre>
</li>
<li>
<p>The three-statement sequence</p>
<pre><code>x = a[i]
y = b[x]
a[i] = y
</code></pre>
</li>
</ol>
<hr />
<h2 id="note-1"><a class="header" href="#note-1">Note</a></h2>
<h4 id="1-指令长度"><a class="header" href="#1-指令长度">1. 指令长度</a></h4>
<pre><code>120:  ST 364, #140
132:  BR 200
140:  ACTION2
</code></pre>
<p>图 8-4 部分代码</p>
<ul>
<li>每行指令前面的标号代表了这行代码的起始位置（即偏移量），和下一行指令的标号差代表这行指令的长度。</li>
<li>第一行有 1 个指令和 2 个常量，所以指令长度是 12，同理第二行有 1 个指令和 1 个常量，所以长度为 8.</li>
</ul>
<pre><code>100:  LD, SP, #600
108:  ACTION1
128:  ADD SP, SP, #msize
136:  ST *SP, #152
</code></pre>
<p>图 8-6 部分代码</p>
<ul>
<li>由于 SP 不占空间，所以上图中的几行指令长度均为 8。</li>
</ul>
<div style="break-before: page; page-break-before: always;"></div><h1 id="exercises-for-section-84"><a class="header" href="#exercises-for-section-84">Exercises for Section 8.4</a></h1>
<h3 id="841"><a class="header" href="#841">8.4.1</a></h3>
<p>Figure 8.10 is a simple matrix-multiplication program.</p>
<ol>
<li>Translate the program into three-address statements of the type we have been using in this section. Assume the matrix entries are numbers that require 8 bytes, and that matrices are stored in row-major order.</li>
<li>Construct the flow graph for your code from (a).</li>
<li>Identify the loops in your flow graph from (b).</li>
</ol>
<pre><code>for (i=O; i&lt;n; i++)
    for (j=O; j&lt;n; j++)
        c[i][j] = 0.0;
for (i=O; i&lt;n; i++)
    for (j=O; j&lt;n; j++)
        for (k=O; k&lt;n; k++)
            ￼c[i][j] = c[i][j] + a[i][k]*b[k][j];
</code></pre>
<p>Figure 8.10: A matrix-multiplication algorithm</p>
<h4 id="answer-77"><a class="header" href="#answer-77">Answer</a></h4>
<ol>
<li>
<p>three-address statements</p>
<pre><code>B1       1)  i = 0

B2       2)  if i &gt;= n goto(13)

B3       3)  j = 0

B4       4)  if j &gt;= n goto(11)

B5       5） t1 = n * i
         6)  t2 = t1 + j
         7)  t3 = t2 * 8
         8)  c[t3] = 0.0
         9)  j = j + 1
        10)  goto(4)

B6      11)  i = i + 1
        12)  goto(2)

B7      13)  i = 0

B8      14)  if i &gt;= n goto(40)

B9      15)  j = 0

B10     16)  if j &gt;= n goto(38)

B11     17)  k = 0

B12     18)  if k &gt;= n goto(36)

B13     19)  t4 = n * i
        20)  t5 = t4 + j
        21)  t6 = t5 * 8
        22)  t7 = c[t6]
        23)  t8 = n * i
        24)  t9 = t8 + k
        25)  t10 = t9 * 8
        26)  t11 = a[t10]
        27)  t12 = n * k
        28)  t13 = t12 + j
        29)  t14 = t13 * 8
        30)  t15 = b[t14]
        31)  t16 = t11 * t15
        32)  t17 = t7 + t16
        33)  c[t6] = t17
        34)  k = k + 1
        35)  goto(18)

B14     36)  j = j + 1
        37)  goto(16)

B15     38)  i = i + 1
        39)  goto(14)
</code></pre>
</li>
<li>
<p>flow graph</p>
<p><img src="https://f.cloud.github.com/assets/340282/1368058/d28ce9f8-397c-11e3-90ae-155b6f5f21fa.gif" alt="8 4 1-2" /></p>
</li>
<li>
<p>loops</p>
<ul>
<li>{B2, B3, B4, B6}</li>
<li>{B4, B5}</li>
<li>{B8, B9, B10, B15}</li>
<li>{B10, B11, B12, B14}</li>
<li>{B12, B13}</li>
</ul>
</li>
</ol>
<h3 id="842"><a class="header" href="#842">8.4.2</a></h3>
<p>Figure 8.11 is code to count the number of primes from 2 to n, using the sieve method on a suitably large array a. That is, a[i] is TRUE at the end only if there is no prime i^0.5 or less that evenly divides i. We initialize all a[i] to TRUE and then set a[j] to FALSE if we find a divisor of j.</p>
<ol>
<li>Translate the program into three-address statements of the type we have been using in this section. Assume integers require 4 bytes.</li>
<li>Construct the flow graph for your code from (a).</li>
<li>Identify the loops in your flow graph from (b).</li>
</ol>
<pre><code>for (i=2; i&lt;=n; i++)
    a[i] = TRUE;
count = 0;
s = sqrt(n);
for (i=2; i&lt;=s; i++)
if (a[i]) 1* i has been found to be a prime *1 {
    count++ ;
    for (j=2*i; j&lt;=n; j = j+i)
        a[j] = FALSE; 1* no multiple of i is a prime *1
    }
</code></pre>
<p>Figure 8.11: Code to sieve for primes</p>
<h4 id="answer-78"><a class="header" href="#answer-78">Answer</a></h4>
<ol>
<li>
<p>three-address statements</p>
<pre><code>B1       1)  i = 2

B2       2)  if i &gt; n goto(7)

B3       3)  t1 = i * 4
         4)  a[t1] = TRUE
         5)  i = i + 1
         6)  goto(2)

B4       7)  count = 0
         8)  s = sqrt(n)
         9)  i = 2

B5      10)  if i &gt; s goto(22)

B6      11)  t2 = i * 4
        12)  ifFalse a[t2] goto(20)

B7      13)  count = count + 1
        14)  j = 2 * i

B8      15)  if j &gt; n goto(20)

B9      16)  t3 = j * 4
        17)  a[t3] = FALSE
        18） j = j + i
        19)  goto(15)

B10     20)  i = i + 1
        21)  goto(10)
</code></pre>
</li>
<li>
<p>flow graph</p>
<p><img src="https://f.cloud.github.com/assets/340282/1368108/b06992fe-3981-11e3-9f51-24f223030901.gif" alt="8 4 2-2" /></p>
</li>
<li>
<p>loops</p>
<ul>
<li>{B2, B3}</li>
<li>{B5, B6, B10}</li>
<li>{B5, B6, B7, B8, B10}</li>
<li>{B8, B9}</li>
</ul>
</li>
</ol>
<hr />
<h3 id="note-2"><a class="header" href="#note-2">Note</a></h3>
<h4 id="1-a-demo-for-algorithm-87-determining-the-liveness-and-next-use-information-foreach-statement-in-a-basic-block"><a class="header" href="#1-a-demo-for-algorithm-87-determining-the-liveness-and-next-use-information-foreach-statement-in-a-basic-block">1. A demo for algorithm 8.7: Determining the liveness and next-use information foreach statement in a basic block.</a></h4>
<pre><code>init:

three-address statements                 symbol table

                                         symbol  live   nextuse
    i)  a = b + c                       [a,      true,  null]
    j)  t = a + b                       [b,      true,  null]
                                        [c,      true,  null]
                                        [t,      true,  null]

step1:
Attach to statement j the information currently found in the symbol table

                                         symbol  live   nextuse
    i)  a = b + c                       [a,      true,  null]
    j)  t = a + b  [t, true, null]      [b,      true,  null]
                   [a, true, null]      [c,      true,  null]
                   [b, true, null]      [t,      true,  null]

step2:
In the symbol table, set x.live = false and
                         x.nextuse = null

                                         symbol  live   nextuse
    i)  a = b + c                       [a,      true,  null]
    j)  t = a + b  [t, true, null]      [b,      true,  null]
                   [a, true, null]      [c,      true,  null]
                   [b, true, null]      [t,      false, null]

step3:
In the symbol table, set a.live = true, b.live = true and
                         a.nextuse = j, b.nextuse = j

                                         symbol  live   nextuse
    i)  a = b + c                       [a,      true,  j   ]
    j)  t = a + b  [t, true, null]      [b,      true,  j   ]
                   [a, true, null]      [c,      true,  null]
                   [b, true, null]      [t,      false, null]

step4:


                                         symbol  live   nextuse
    i)  a = b + c  [a, true, j   ]      [a,      true,  j   ]
                   [b, true, j   ]      [b,      true,  j   ]
                   [c, true, null]      [c,      true,  null]
                                        [t,      false, null]
    j)  t = a + b  [t, true, null]
                   [a, true, null]
                   [b, true, null]

step5:

                                         symbol  live   nextuse
    i)  a = b + c  [a, true, j   ]      [a,      false, null]
                   [b, true, j   ]      [b,      true,  j   ]
                   [c, true, null]      [c,      true,  null]
                                        [t,      false, null]
    j)  t = a + b  [t, true, null]
                   [a, true, null]
                   [b, true, null]

step6:

                                         symbol  live   nextuse
    i)  a = b + c  [a, true, j   ]      [a,      false, null]
                   [b, true, j   ]      [b,      true,  i   ]
                   [c, true, null]      [c,      true,  i   ]
                                        [t,      false, null]
    j)  t = a + b  [t, true, null]
                   [a, true, null]
                   [b, true, null]

</code></pre>
<h4 id="2-three-ways-to-generate-code-for-fori--0-i--n--i-statement"><a class="header" href="#2-three-ways-to-generate-code-for-fori--0-i--n--i-statement">2. Three ways to generate code for &quot;for(i = 0; i &lt; n ; i++)&quot; statement</a></h4>
<pre><code> 1) i = 0
 2) if i &gt;= n goto(9)
 3)
    ...
 7) i = i + 1
 8) if i &lt; n goto(3)
 9)


 1) i = 0
 2) goto(8)
 3)
    ...
 7) i = i + 1
 8) if i &lt; n goto(3)
 9)


 1) i= 0
 2) if i &gt;= n goto(9)
    ...
 7) i = i + 1
 8) goto(2)
 9)
</code></pre>
<p>更多可参考 RednaxelaFX 的 <a href="http://rednaxelafx.iteye.com/blog/1961217">对C语义的for循环的基本代码生成模式</a></p>
<div style="break-before: page; page-break-before: always;"></div><h1 id="exercises-for-section-85"><a class="header" href="#exercises-for-section-85">Exercises for Section 8.5</a></h1>
<h3 id="851"><a class="header" href="#851">8.5.1</a></h3>
<p>Construct the DAG for the basic block</p>
<pre><code>d = b * c
e = a + b
b = b * c
a = e - d
</code></pre>
<h4 id="answer-79"><a class="header" href="#answer-79">Answer</a></h4>
<p><img src="https://f.cloud.github.com/assets/340282/1357594/df203a26-379c-11e3-970b-349a410c6cb5.gif" alt="8 5 1" /></p>
<h3 id="852"><a class="header" href="#852">8.5.2</a></h3>
<p>Simplify the three-address code of Exercise 8.5.1, assuming</p>
<ol>
<li>Only a is live on exit from the block.</li>
<li>a, b, and c are live on exit from the block.</li>
</ol>
<h4 id="answer-80"><a class="header" href="#answer-80">Answer</a></h4>
<ol>
<li>
<p>Only a is live on exit from the block.</p>
<pre><code>e = a + b
d = b * c
a = e - d
</code></pre>
</li>
<li>
<p>a, b, and c are live on exit from the block.</p>
<pre><code>e = a + b
b = b * c
a = e - b
</code></pre>
</li>
</ol>
<h3 id="853"><a class="header" href="#853">8.5.3</a></h3>
<p>Construct the basic block for the code in block B6 of Fig. 8.9. Do not forget to include the comparison i &lt;= 10.</p>
<h4 id="answer-81"><a class="header" href="#answer-81">Answer</a></h4>
<p><img src="https://f.cloud.github.com/assets/340282/1365769/12f90536-388c-11e3-9892-643783ee9915.gif" alt="8 5 3" /></p>
<h4 id="疑问"><a class="header" href="#疑问">疑问</a></h4>
<ul>
<li>“Construct the basic block” 被翻译成 “构造 DAG”，是这个意思吗？</li>
<li>如何为一个 “if goto” 语句 construct the basic block？</li>
</ul>
<h3 id="854"><a class="header" href="#854">8.5.4</a></h3>
<p>Construct the DAG for the code in block B3 of Fig. 8.9.</p>
<h4 id="answer-82"><a class="header" href="#answer-82">Answer</a></h4>
<p><img src="https://f.cloud.github.com/assets/340282/1365782/396accf2-388e-11e3-946b-7154333ba871.gif" alt="8 5 4" /></p>
<h3 id="855"><a class="header" href="#855">8.5.5</a></h3>
<p>Extend Algorithm 8.7 to process three-statements of the form</p>
<ol>
<li>a[i] = b</li>
<li>a = b[i]</li>
<li>a = *b</li>
<li>*a = b</li>
</ol>
<h3 id="856"><a class="header" href="#856">8.5.6</a></h3>
<p>Construct the DAG for the basic block</p>
<pre><code>a[i] = b
*p = c
d = a[j]
e = *p
*p = a[i]
</code></pre>
<p>on the assumption that</p>
<ol>
<li>p can point anywhere.</li>
<li>p can point only to b or d.</li>
</ol>
<h4 id="疑问-1"><a class="header" href="#疑问-1">疑问</a></h4>
<p>8.5.6 节讲指针赋值这里又没有 demo 啊！！！</p>
<ul>
<li><code>*p = c</code> 和 <code>c = *p</code>翻译成 DAG 是不是这样的：<img src="https://f.cloud.github.com/assets/340282/1365867/563bfc66-3898-11e3-9b2b-f536f294e165.png" alt="screen shot 2013-10-19 at 4 27 34 pm" /></li>
<li><code>*p = a[i]</code> 这样的语句用 DAG 如何表示？</li>
<li>8.5.6 节讲到：the operator =* must take all nodes that are currently associated with identifiers as arguments。这句话再 DAG 中如何表示？</li>
</ul>
<h3 id="857-"><a class="header" href="#857-">8.5.7 !</a></h3>
<p>If a pointer or array expression, such as a[i] or *p is assigned and then used, without the possibility of being changed in the interim, we can take advantage of the situation to simplify the DAG. For example, in the code of Exercise 8.5.6, since p is not assigned between the second and fourth statements,the statement e = *p can be replaced by e = c, regardless of what p points to. Revise the DAG-construction algorithm to take advantage of such situations, and apply your algorithm to the code of Example 8.5.6.</p>
<h3 id="858"><a class="header" href="#858">8.5.8</a></h3>
<p>Suppose a basic block is formed from the C assignment statements</p>
<pre><code>x = a + b + c + d + e + f;
y = a + c + e;
</code></pre>
<ol>
<li>Give the three-address statements (only one addition per statement) for this block.</li>
<li>Use the associative and commutative laws to modify the block to use the fewest possible number of instructions, assuming both x and y are live on exit from the block.</li>
</ol>
<h4 id="answer-83"><a class="header" href="#answer-83">Answer</a></h4>
<ol>
<li>
<p>three-address statements</p>
<pre><code>t1 = a + b
t2 = t1 + c
t3 = t2 + d
t4 = t3 + e
t5 = t4 + f
x = t5
t6 = a + c
t7 = c + e
y = t6 + t7
</code></pre>
</li>
<li>
<p>optimized statments</p>
<pre><code>t1 = a + c
t2 = t1 + e
y = t2
t3 = t2 + b
t4 = t3 + d
t5 = t4 + f
x = t5
</code></pre>
</li>
</ol>

                    </main>

                    <nav class="nav-wrapper" aria-label="Page navigation">
                        <!-- Mobile navigation buttons -->


                        <div style="clear: both"></div>
                    </nav>
                </div>
            </div>

            <nav class="nav-wide-wrapper" aria-label="Page navigation">

            </nav>

        </div>




        <script type="text/javascript">
            window.playground_copyable = true;
        </script>


        <script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
        <script src="mark.min.js" type="text/javascript" charset="utf-8"></script>
        <script src="searcher.js" type="text/javascript" charset="utf-8"></script>

        <script src="clipboard.min.js" type="text/javascript" charset="utf-8"></script>
        <script src="highlight.js" type="text/javascript" charset="utf-8"></script>
        <script src="book.js" type="text/javascript" charset="utf-8"></script>

        <!-- Custom JS scripts -->

        <script type="text/javascript">
        window.addEventListener('load', function() {
            window.setTimeout(window.print, 100);
        });
        </script>

    </body>
</html>
